mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2025-01-22 08:11:47 -05:00
initial event loop implementation
This commit is contained in:
parent
92b5ffb5b1
commit
39fb9da8ae
10 changed files with 135 additions and 55 deletions
|
@ -14,21 +14,25 @@
|
|||
#include <unistd.h>
|
||||
#include <vanilla.h>
|
||||
|
||||
void vanillaEventHandler(void *context, int type, const char *data, size_t dataLength)
|
||||
void Backend::vanillaEventHandler()
|
||||
{
|
||||
Backend *backend = static_cast<Backend*>(context);
|
||||
vanilla_event_t event;
|
||||
|
||||
switch (type) {
|
||||
case VANILLA_EVENT_VIDEO:
|
||||
emit backend->videoAvailable(QByteArray(data, dataLength));
|
||||
break;
|
||||
case VANILLA_EVENT_AUDIO:
|
||||
emit backend->audioAvailable(QByteArray(data, dataLength));
|
||||
break;
|
||||
case VANILLA_EVENT_VIBRATE:
|
||||
emit backend->vibrate(*data);
|
||||
break;
|
||||
while (vanilla_wait_event(&event)) {
|
||||
switch (event.type) {
|
||||
case VANILLA_EVENT_VIDEO:
|
||||
emit videoAvailable(QByteArray((const char *) event.data, event.size));
|
||||
break;
|
||||
case VANILLA_EVENT_AUDIO:
|
||||
emit audioAvailable(QByteArray((const char *) event.data, event.size));
|
||||
break;
|
||||
case VANILLA_EVENT_VIBRATE:
|
||||
emit vibrate(*event.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add way for this loop to exit, preferably from libvanilla
|
||||
}
|
||||
|
||||
Backend::Backend(QObject *parent) : QObject(parent)
|
||||
|
@ -71,11 +75,12 @@ int Backend::syncInternal(uint16_t code)
|
|||
void Backend::connectToConsole()
|
||||
{
|
||||
connectInternal();
|
||||
QtConcurrent::run(&Backend::vanillaEventHandler, this);
|
||||
}
|
||||
|
||||
int Backend::connectInternal()
|
||||
{
|
||||
return vanilla_start(vanillaEventHandler, this);
|
||||
return vanilla_start(0);
|
||||
}
|
||||
|
||||
void Backend::updateTouch(int x, int y)
|
||||
|
@ -174,7 +179,7 @@ int BackendViaInternalPipe::syncInternal(uint16_t code)
|
|||
|
||||
int BackendViaInternalPipe::connectInternal()
|
||||
{
|
||||
return vanilla_start_udp(vanillaEventHandler, this, QHostAddress(QHostAddress::LocalHost).toIPv4Address());
|
||||
return vanilla_start(QHostAddress(QHostAddress::LocalHost).toIPv4Address());
|
||||
}
|
||||
|
||||
BackendViaExternalPipe::BackendViaExternalPipe(const QHostAddress &udpServer, QObject *parent) : Backend(parent)
|
||||
|
@ -189,5 +194,5 @@ int BackendViaExternalPipe::syncInternal(uint16_t code)
|
|||
|
||||
int BackendViaExternalPipe::connectInternal()
|
||||
{
|
||||
return vanilla_start_udp(vanillaEventHandler, this, m_serverAddress.toIPv4Address());
|
||||
return vanilla_start(m_serverAddress.toIPv4Address());
|
||||
}
|
|
@ -75,6 +75,8 @@ protected:
|
|||
private slots:
|
||||
void syncFutureCompleted();
|
||||
|
||||
void vanillaEventHandler();
|
||||
|
||||
};
|
||||
|
||||
class BackendViaInternalPipe : public Backend
|
||||
|
|
|
@ -31,7 +31,7 @@ typedef struct {
|
|||
uint32_t video_format;
|
||||
} AudioPacketVideoFormat;
|
||||
|
||||
void handle_audio_packet(vanilla_event_handler_t event_handler, void *context, char *data, size_t len)
|
||||
void handle_audio_packet(gamepad_context_t *ctx, char *data, size_t len)
|
||||
{
|
||||
for (int byte = 0; byte < len; byte++) {
|
||||
data[byte] = (unsigned char) reverse_bits(data[byte], 8);
|
||||
|
@ -56,22 +56,22 @@ void handle_audio_packet(vanilla_event_handler_t event_handler, void *context, c
|
|||
return;
|
||||
}
|
||||
|
||||
event_handler(context, VANILLA_EVENT_AUDIO, ap->payload, ap->payload_size);
|
||||
push_event(ctx, VANILLA_EVENT_AUDIO, ap->payload, ap->payload_size);
|
||||
|
||||
uint8_t vibrate_val = ap->vibrate;
|
||||
event_handler(context, VANILLA_EVENT_VIBRATE, &vibrate_val, sizeof(vibrate_val));
|
||||
push_event(ctx, VANILLA_EVENT_VIBRATE, &vibrate_val, sizeof(vibrate_val));
|
||||
}
|
||||
|
||||
void *listen_audio(void *x)
|
||||
{
|
||||
struct gamepad_thread_context *info = (struct gamepad_thread_context *) x;
|
||||
gamepad_context_t *info = (gamepad_context_t *) x;
|
||||
unsigned char data[2048];
|
||||
ssize_t size;
|
||||
do {
|
||||
size = recv(info->socket_aud, data, sizeof(data), 0);
|
||||
if (size > 0) {
|
||||
if (is_stop_code(data, size)) break;
|
||||
handle_audio_packet(info->event_handler, info->context, data, size);
|
||||
handle_audio_packet(info, data, size);
|
||||
}
|
||||
} while (!is_interrupted());
|
||||
|
||||
|
|
|
@ -420,7 +420,7 @@ void handle_command_packet(int skt, CmdHeader *request)
|
|||
|
||||
void *listen_command(void *x)
|
||||
{
|
||||
struct gamepad_thread_context *info = (struct gamepad_thread_context *)x;
|
||||
gamepad_context_t *info = (gamepad_context_t *)x;
|
||||
|
||||
unsigned char data[sizeof(CmdHeader) + 2048];
|
||||
ssize_t size;
|
||||
|
|
|
@ -178,7 +178,7 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int connect_as_gamepad_internal(vanilla_event_handler_t event_handler, void *context, uint32_t server_address)
|
||||
int connect_as_gamepad_internal(event_loop_t *event_loop, uint32_t server_address)
|
||||
{
|
||||
clear_interrupt();
|
||||
|
||||
|
@ -199,9 +199,8 @@ int connect_as_gamepad_internal(vanilla_event_handler_t event_handler, void *con
|
|||
PORT_CMD += 200;
|
||||
}
|
||||
|
||||
struct gamepad_thread_context info;
|
||||
info.event_handler = event_handler;
|
||||
info.context = context;
|
||||
gamepad_context_t info;
|
||||
info.event_loop = event_loop;
|
||||
|
||||
int ret = VANILLA_ERROR;
|
||||
|
||||
|
@ -270,4 +269,25 @@ exit:
|
|||
int is_stop_code(const char *data, size_t data_length)
|
||||
{
|
||||
return (data_length == sizeof(STOP_CODE) && !memcmp(data, &STOP_CODE, sizeof(STOP_CODE)));
|
||||
}
|
||||
|
||||
int push_event(gamepad_context_t *ctx, int type, const void *data, size_t size)
|
||||
{
|
||||
pthread_mutex_lock(&ctx->event_loop->mutex);
|
||||
|
||||
vanilla_event_t *ev = &ctx->event_loop->events[ctx->event_loop->new_index % VANILLA_MAX_EVENT_COUNT];
|
||||
|
||||
ev->type = type;
|
||||
memcpy(ev->data, data, size);
|
||||
ev->size = size;
|
||||
|
||||
ctx->event_loop->new_index++;
|
||||
|
||||
// Prevent rollover by skipping oldest event if necessary
|
||||
if (ctx->event_loop->new_index > ctx->event_loop->used_index - VANILLA_MAX_EVENT_COUNT) {
|
||||
ctx->event_loop->used_index++;
|
||||
}
|
||||
|
||||
pthread_cond_broadcast(&ctx->event_loop->waitcond);
|
||||
pthread_mutex_unlock(&ctx->event_loop->mutex);
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "vanilla.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint16_t PORT_MSG;
|
||||
|
@ -13,22 +14,31 @@ extern uint16_t PORT_CMD;
|
|||
|
||||
struct wpa_ctrl;
|
||||
|
||||
struct gamepad_thread_context
|
||||
#define VANILLA_MAX_EVENT_COUNT 20
|
||||
typedef struct
|
||||
{
|
||||
vanilla_event_handler_t event_handler;
|
||||
void *context;
|
||||
vanilla_event_t events[VANILLA_MAX_EVENT_COUNT];
|
||||
size_t new_index;
|
||||
size_t used_index;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t waitcond;
|
||||
} event_loop_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
event_loop_t *event_loop;
|
||||
int socket_vid;
|
||||
int socket_aud;
|
||||
int socket_hid;
|
||||
int socket_msg;
|
||||
int socket_cmd;
|
||||
};
|
||||
} gamepad_context_t;
|
||||
|
||||
int sync_internal(uint16_t code, uint32_t server_address);
|
||||
int connect_as_gamepad_internal(vanilla_event_handler_t event_handler, void *context, uint32_t server_address);
|
||||
int connect_as_gamepad_internal(event_loop_t *ctx, uint32_t server_address);
|
||||
unsigned int reverse_bits(unsigned int b, int bit_count);
|
||||
void send_to_console(int fd, const void *data, size_t data_size, int port);
|
||||
int is_stop_code(const char *data, size_t data_length);
|
||||
int push_event(gamepad_context_t *ctx, int type, const void *data, size_t size);
|
||||
|
||||
#endif // VANILLA_GAMEPAD_H
|
|
@ -243,7 +243,7 @@ void send_input(int socket_hid)
|
|||
|
||||
void *listen_input(void *x)
|
||||
{
|
||||
struct gamepad_thread_context *info = (struct gamepad_thread_context *) x;
|
||||
gamepad_context_t *info = (gamepad_context_t *) x;
|
||||
|
||||
pthread_mutex_init(&button_mtx, NULL);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void send_idr_request_to_console(int socket_msg)
|
|||
send_to_console(socket_msg, idr_request, sizeof(idr_request), PORT_MSG);
|
||||
}
|
||||
|
||||
void handle_video_packet(vanilla_event_handler_t event_handler, void *context, unsigned char *data, size_t size, int socket_msg)
|
||||
void handle_video_packet(gamepad_context_t *ctx, unsigned char *data, size_t size, int socket_msg)
|
||||
{
|
||||
// TODO: This is all really weird. Copied from drc-sim-c but I feel like there's probably a better way.
|
||||
|
||||
|
@ -176,7 +176,7 @@ void handle_video_packet(vanilla_event_handler_t event_handler, void *context, u
|
|||
nals_current++;
|
||||
}
|
||||
|
||||
event_handler(context, VANILLA_EVENT_VIDEO, nals, (nals_current - nals));
|
||||
push_event(ctx, VANILLA_EVENT_VIDEO, nals, (nals_current - nals));
|
||||
|
||||
free(nals);
|
||||
} else {
|
||||
|
@ -188,7 +188,7 @@ void handle_video_packet(vanilla_event_handler_t event_handler, void *context, u
|
|||
void *listen_video(void *x)
|
||||
{
|
||||
// Receive video
|
||||
struct gamepad_thread_context *info = (struct gamepad_thread_context *) x;
|
||||
gamepad_context_t *info = (gamepad_context_t *) x;
|
||||
unsigned char data[2048];
|
||||
ssize_t size;
|
||||
|
||||
|
@ -198,7 +198,7 @@ void *listen_video(void *x)
|
|||
size = recv(info->socket_vid, data, sizeof(data), 0);
|
||||
if (size > 0) {
|
||||
if (is_stop_code(data, size)) break;
|
||||
handle_video_packet(info->event_handler, info->context, data, size, info->socket_msg);
|
||||
handle_video_packet(info, data, size, info->socket_msg);
|
||||
}
|
||||
} while (!is_interrupted());
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -14,31 +15,40 @@
|
|||
#include "vanilla.h"
|
||||
|
||||
pthread_mutex_t main_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t gamepad_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
event_loop_t event_loop = {0};
|
||||
|
||||
struct gamepad_data_t
|
||||
{
|
||||
vanilla_event_handler_t event_handler;
|
||||
void *context;
|
||||
uint32_t server_address;
|
||||
};
|
||||
|
||||
void *start_gamepad(void *arg)
|
||||
{
|
||||
struct gamepad_data_t *data = (struct gamepad_data_t *) arg;
|
||||
connect_as_gamepad_internal(data->event_handler, data->context, data->server_address);
|
||||
|
||||
// Initialize gamepad
|
||||
event_loop.new_index = 0;
|
||||
event_loop.used_index = 0;
|
||||
pthread_mutex_init(&event_loop.mutex, NULL);
|
||||
pthread_cond_init(&event_loop.waitcond, NULL);
|
||||
|
||||
connect_as_gamepad_internal(&event_loop, data->server_address);
|
||||
|
||||
pthread_cond_destroy(&event_loop.waitcond);
|
||||
pthread_mutex_destroy(&event_loop.mutex);
|
||||
|
||||
free(data);
|
||||
pthread_mutex_unlock(&main_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vanilla_start_internal(vanilla_event_handler_t event_handler, void *context, uint32_t server_address)
|
||||
int vanilla_start_internal(uint32_t server_address)
|
||||
{
|
||||
if (pthread_mutex_trylock(&main_mutex) == 0) {
|
||||
pthread_t other;
|
||||
|
||||
struct gamepad_data_t *data = malloc(sizeof(struct gamepad_data_t));
|
||||
data->event_handler = event_handler;
|
||||
data->context = context;
|
||||
data->server_address = server_address;
|
||||
|
||||
pthread_create(&other, NULL, start_gamepad, data);
|
||||
|
@ -48,14 +58,9 @@ int vanilla_start_internal(vanilla_event_handler_t event_handler, void *context,
|
|||
}
|
||||
}
|
||||
|
||||
int vanilla_start(vanilla_event_handler_t event_handler, void *context)
|
||||
int vanilla_start(uint32_t server_address)
|
||||
{
|
||||
return vanilla_start_internal(event_handler, context, 0);
|
||||
}
|
||||
|
||||
int vanilla_start_udp(vanilla_event_handler_t event_handler, void *context, uint32_t server_address)
|
||||
{
|
||||
return vanilla_start_internal(event_handler, context, server_address);
|
||||
return vanilla_start_internal(server_address);
|
||||
}
|
||||
|
||||
void vanilla_stop()
|
||||
|
@ -137,4 +142,38 @@ void vanilla_set_battery_status(int battery_status)
|
|||
int vanilla_sync(uint16_t code, uint32_t server_address)
|
||||
{
|
||||
return sync_internal(code, server_address);
|
||||
}
|
||||
|
||||
int vanilla_get_event(vanilla_event_t *event, int wait)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pthread_mutex_lock(&event_loop.mutex);
|
||||
|
||||
if (wait) {
|
||||
while (event_loop.used_index == event_loop.new_index) {
|
||||
pthread_cond_wait(&event_loop.waitcond, &event_loop.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (event_loop.used_index < event_loop.new_index) {
|
||||
// Output data to pointer
|
||||
*event = event_loop.events[event_loop.used_index % VANILLA_MAX_EVENT_COUNT];
|
||||
event_loop.used_index++;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&event_loop.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vanilla_poll_event(vanilla_event_t *event)
|
||||
{
|
||||
return vanilla_get_event(event, 0);
|
||||
}
|
||||
|
||||
int vanilla_wait_event(vanilla_event_t *event)
|
||||
{
|
||||
return vanilla_get_event(event, 1);
|
||||
}
|
|
@ -60,6 +60,7 @@ enum VanillaGamepadButtons
|
|||
|
||||
enum VanillaEvent
|
||||
{
|
||||
VANILLA_EVENT_NONE,
|
||||
VANILLA_EVENT_VIDEO,
|
||||
VANILLA_EVENT_AUDIO,
|
||||
VANILLA_EVENT_VIBRATE
|
||||
|
@ -94,19 +95,22 @@ static const uint8_t VANILLA_PPS_PARAMS[] = {
|
|||
0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x06, 0x0c, 0xe8
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler used by caller to receive events
|
||||
*/
|
||||
typedef void (*vanilla_event_handler_t)(void *context, int event_type, const char *data, size_t data_size);
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
uint8_t data[2048];
|
||||
size_t size;
|
||||
} vanilla_event_t;
|
||||
|
||||
/**
|
||||
* Start listening for gamepad commands
|
||||
*/
|
||||
int vanilla_start(vanilla_event_handler_t event_handler, void *context);
|
||||
int vanilla_start_udp(vanilla_event_handler_t event_handler, void *context, uint32_t server_address);
|
||||
|
||||
int vanilla_start(uint32_t server_address);
|
||||
int vanilla_sync(uint16_t code, uint32_t server_address);
|
||||
|
||||
int vanilla_poll_event(vanilla_event_t *event);
|
||||
int vanilla_wait_event(vanilla_event_t *event);
|
||||
|
||||
/**
|
||||
* Attempt to stop the current action
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue