Skip to content

Commit

Permalink
Windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
SeppNel committed Oct 8, 2024
1 parent e1505e6 commit fde3fa5
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 114 deletions.
172 changes: 81 additions & 91 deletions cemuhookprotocol.h
Original file line number Diff line number Diff line change
@@ -1,100 +1,90 @@
#include <cstdint>

namespace cemuhook::protocol
{
#pragma pack(push, 1)
struct Header
{
char magic[4]; // DSUS - server, DSUC - client
uint16_t version; // 1001
uint16_t length; // without header
uint32_t crc32; // whole packet with this field = 0
uint32_t id; // of packet source, constant among one run
uint32_t eventType; // no part of the header where length is involved
// event types:
// 0x100000 - protocol version information
// 0x100001 - information about connected controllers
// 0x100002 - actual controllers data
};

namespace cemuhook_protocol {
#pragma pack(push, 1)
struct Header {
char magic[4]; // DSUS - server, DSUC - client
uint16_t version; // 1001
uint16_t length; // without header
uint32_t crc32; // whole packet with this field = 0
uint32_t id; // of packet source, constant among one run
uint32_t eventType; // no part of the header where length is involved
// event types:
// 0x100000 - protocol version information
// 0x100001 - information about connected controllers
// 0x100002 - actual controllers data
};

struct VersionInformation
{
Header header;
uint16_t version;
};
struct VersionInformation {
Header header;
uint16_t version;
};

struct SharedResponse
{
uint8_t slot;
uint8_t slotState; // 0 - not connected, 1 - reserved, 2 - connected
uint8_t deviceModel; // 0 - not applicable, 1 - no or partial gyro, 2 - full gyro, 3 - do not use
uint8_t connection; // 0 - not applicable, 1 - USB, 2 - bluetooth
uint32_t mac1; // unused - 0
uint16_t mac2; // unused - 0
uint8_t battery; // unused - 0
};
struct SharedResponse {
uint8_t slot;
uint8_t slotState; // 0 - not connected, 1 - reserved, 2 - connected
uint8_t deviceModel; // 0 - not applicable, 1 - no or partial gyro, 2 - full gyro, 3 - do not use
uint8_t connection; // 0 - not applicable, 1 - USB, 2 - bluetooth
uint32_t mac1; // unused - 0
uint16_t mac2; // unused - 0
uint8_t battery; // unused - 0
};

struct InfoRequest
{
int32_t portCnt; // amount of ports to report
uint8_t slots[4];
};
struct InfoRequest {
int32_t portCnt; // amount of ports to report
uint8_t slots[4];
};

struct InfoAnswer
{
Header header;
SharedResponse response;
uint8_t zero;
};
struct InfoAnswer {
Header header;
SharedResponse response;
uint8_t zero;
};

struct SubscribeRequest
{
uint8_t mask; // 1 slot-based, 2 - mac-base, 3 - both, 0 - all controllers
uint8_t slot; // slot to subscribe
uint32_t mac1; // unused
uint16_t mac2; // unused
};
struct SubscribeRequest {
uint8_t mask; // 1 slot-based, 2 - mac-base, 3 - both, 0 - all controllers
uint8_t slot; // slot to subscribe
uint32_t mac1; // unused
uint16_t mac2; // unused
};

struct MotionData
{
uint64_t timestamp;
float accX;
float accY;
float accZ;
float pitch;
float yaw;
float roll;
};
struct MotionData {
uint64_t timestamp;
float accX;
float accY;
float accZ;
float pitch;
float yaw;
float roll;
};

struct DataEvent
{
Header header;
SharedResponse response;
uint8_t connected;
uint32_t packetNumber;
uint8_t buttons1;
uint8_t buttons2;
uint8_t homeButton;
uint8_t touchButton;
uint8_t lsX;
uint8_t lsY;
uint8_t rsX;
uint8_t rsY;
uint8_t adLeft;
uint8_t adDown;
uint8_t adRight;
uint8_t adUp;
uint8_t aY;
uint8_t aB;
uint8_t aA;
uint8_t aX;
uint8_t aR1;
uint8_t aL1;
uint8_t aR2;
uint8_t aL2;
uint32_t touch[3];
MotionData motion;
};
#pragma pack(pop)
}
struct DataEvent {
Header header;
SharedResponse response;
uint8_t connected;
uint32_t packetNumber;
uint8_t buttons1;
uint8_t buttons2;
uint8_t homeButton;
uint8_t touchButton;
uint8_t lsX;
uint8_t lsY;
uint8_t rsX;
uint8_t rsY;
uint8_t adLeft;
uint8_t adDown;
uint8_t adRight;
uint8_t adUp;
uint8_t aY;
uint8_t aB;
uint8_t aA;
uint8_t aX;
uint8_t aR1;
uint8_t aL1;
uint8_t aR2;
uint8_t aL2;
uint32_t touch[3];
MotionData motion;
};
#pragma pack(pop)
} // namespace cemuhook_protocol
26 changes: 8 additions & 18 deletions cemuhookserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_gamecontroller.h>
#include <algorithm>
#include <arpa/inet.h>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <sstream>
#include <sys/socket.h>
#include <sys/types.h>

using std::cout;
Expand All @@ -24,10 +22,6 @@ using namespace std::chrono;
#define INFO_TYPE 0x100001
#define DATA_TYPE 0x100002

const char *GetIP(sockaddr_in const &addr, char *buf) {
return inet_ntop(addr.sin_family, &(addr.sin_addr.s_addr), buf, INET6_ADDRSTRLEN);
}

uint32_t crc32(const unsigned char *s, size_t n) {
uint32_t crc = 0xFFFFFFFF;

Expand All @@ -41,10 +35,6 @@ uint32_t crc32(const unsigned char *s, size_t n) {
return ~crc;
}

ssize_t SendPacket(int const &socketFd, std::pair<uint16_t, void const *> const &outBuf, sockaddr_in const &sockInClient) {
return sendto(socketFd, outBuf.second, outBuf.first, 0, (sockaddr *)&sockInClient, sizeof(sockInClient));
}

Server::Server() {
PrepareAnswerConstants();
configButtons.emplace_back(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, false, 0.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f); // Default: RB = Shake up, no gyro;
Expand Down Expand Up @@ -132,12 +122,11 @@ void Server::PrepareAnswerConstants() {
void Server::Start() {
cout << "Server: Initializing.\n";

crossSockets::initializeSockets();

socketFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

timeval read_timeout;
read_timeout.tv_sec = 2;
read_timeout.tv_usec = 0;
setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout));
crossSockets::setSocketOptionsTimeout(socketFd, 2);

if (socketFd == -1)
throw std::runtime_error("Server: Socket could not be created.");
Expand All @@ -154,7 +143,7 @@ void Server::Start() {

char ipStr[INET6_ADDRSTRLEN];
ipStr[0] = 0;
cout << "Server: Socket created at IP: " << GetIP(sockAddr, ipStr) << " Port: " << ntohs(sockAddr.sin_port) << ".\n";
cout << "Server: Socket created at IP: " << crossSockets::GetIP(sockAddr, ipStr) << " Port: " << ntohs(sockAddr.sin_port) << ".\n";

char buf[BUFLEN];
sockaddr_in sockInClient;
Expand All @@ -174,7 +163,7 @@ void Server::Start() {
Header &header = *reinterpret_cast<Header *>(buf);

std::ostringstream addressTextStream;
addressTextStream << "IP: " << GetIP(sockInClient, ipStr) << " Port: " << ntohs(sockInClient.sin_port);
addressTextStream << "IP: " << crossSockets::GetIP(sockInClient, ipStr) << " Port: " << ntohs(sockInClient.sin_port);
auto addressText = addressTextStream.str();

switch (header.eventType) {
Expand All @@ -186,7 +175,7 @@ void Server::Start() {
InfoRequest &req = *reinterpret_cast<InfoRequest *>(buf + headerSize);
for (int i = 0; i < req.portCnt; i++) {
outBuf = PrepareInfoAnswer(req.slots[i]);
SendPacket(socketFd, outBuf, sockInClient);
crossSockets::SendPacket(socketFd, outBuf, sockInClient);
}
} break;
case DATA_TYPE:
Expand Down Expand Up @@ -239,7 +228,7 @@ void Server::sendTask() {
while (!stopSending) {
outBuf = PrepareDataAnswer(++packet);
for (auto &client : clients) {
SendPacket(socketFd, outBuf, client.address);
crossSockets::SendPacket(socketFd, outBuf, client.address);
}
std::this_thread::sleep_for(microseconds(THREAD_SLEEP_TIME_U));
}
Expand Down Expand Up @@ -306,6 +295,7 @@ SDL_GameController *findController() {
}

void Server::inputTask() {
SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1");
if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) {
cout << "SDL could not initialize! SDL Error: " << SDL_GetError() << std::endl;
return;
Expand Down
9 changes: 4 additions & 5 deletions cemuhookserver.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "cemuhookprotocol.h"
#include "config.h"
#include "crossSockets.h"

#include <cstddef>
#include <mutex>
#include <netinet/in.h>
#include <shared_mutex>
#include <thread>
#include <vector>

using namespace cemuhook::protocol;
using namespace cemuhook_protocol;

class Server {
public:
Expand Down Expand Up @@ -40,7 +41,6 @@ class Server {
std::unique_ptr<std::thread> sendThread;
std::unique_ptr<std::thread> inputThread;

void serverTask();
void sendTask();
void inputTask();

Expand All @@ -52,10 +52,9 @@ class Server {

void PrepareAnswerConstants();

std::pair<uint16_t, void const *> PrepareVersionAnswer(uint32_t const &id);
// std::pair<uint16_t, void const *> PrepareVersionAnswer(uint32_t const &id);
std::pair<uint16_t, void const *> PrepareInfoAnswer(uint8_t const &slot);
std::pair<uint16_t, void const *> PrepareDataAnswer(uint32_t const &packet);
void ModifyDataAnswerId(uint32_t const &id);
void CalcCrcDataAnswer();

std::vector<Client> clients;
Expand Down
53 changes: 53 additions & 0 deletions crossSockets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "crossSockets.h"

namespace crossSockets {

const char *GetIP(sockaddr_in const &addr, char *buf) {
#ifdef __unix__
return inet_ntop(addr.sin_family, &(addr.sin_addr.s_addr), buf, INET6_ADDRSTRLEN);
#endif
#ifdef _WIN32
// TODO
return "TODO";
#endif
}

ssize_t SendPacket(int const &socketFd, std::pair<uint16_t, void const *> const &outBuf, sockaddr_in const &sockInClient) {
#ifdef __unix__
void const *buffer = outBuf.second;
#endif
#ifdef _WIN32
const char *buffer = (const char *)outBuf.second;
#endif

return sendto(socketFd, buffer, outBuf.first, 0, (sockaddr *)&sockInClient, sizeof(sockInClient));
}

void setSocketOptionsTimeout(int socketFd, int secs) {
#ifdef __unix__
timeval read_timeout;
read_timeout.tv_sec = secs;
read_timeout.tv_usec = 0;
setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout));
#endif
#ifdef _WIN32
DWORD timeout = secs * 1000; // Milliseconds
setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
#endif
}

void initializeSockets() {
#ifdef _WIN32
WSADATA wsaData;

// Initialize Winsock (Windows-specific).
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cout << "Server: Winsock initialization failed. Error: " << WSAGetLastError() << std::endl;
return;
}
#endif

return;
}

} // namespace crossSockets
Loading

0 comments on commit fde3fa5

Please sign in to comment.