From 2d3ea3359bee380b9e4c57ccd68dd7930157d919 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Fri, 14 May 2021 22:55:45 +0200 Subject: [PATCH 01/15] [WIP] CLI parsing and check for C socket API compatibility (#25) --- platform-sdl/CMakeLists.txt | 15 +++++++ platform-sdl/source/cli/config.h | 37 +++++++++++++++++ platform-sdl/source/window/window.cpp | 58 ++++++++++++++++++++++----- platform-sdl/source/window/window.h | 4 ++ 4 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 platform-sdl/source/cli/config.h diff --git a/platform-sdl/CMakeLists.txt b/platform-sdl/CMakeLists.txt index 43fd21c..75ada9b 100644 --- a/platform-sdl/CMakeLists.txt +++ b/platform-sdl/CMakeLists.txt @@ -26,6 +26,7 @@ set(HEADERS source/controllers/display_sdl.h source/ui/native_ui.h source/window/window.h + source/cli/config.h ) set(DARWIN_SOURCES @@ -91,6 +92,20 @@ if (OS_MACOS) set_source_files_properties(${DARWIN_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++") endif() +# Check whether we can use sys/socket.h +string(CONFIGURE [[ + #include + + int main() { + sockaddr_in addr; + return 0; + } +]] code @ONLY) +check_cxx_source_compiles("${code}" CAN_COMPILE_WITH_SYS_SOCKET_H) +target_compile_definitions(fb_core PUBLIC -DFB_HAS_SOCKETS=$) + +target_compile_definitions(fb_sdl PRIVATE -DHAS_STD_THIS_THREAD=$) + target_link_libraries(fb_sdl fb_core ${FB_EXTERNAL_LIBS}) fb_use_autosave(fb_core) diff --git a/platform-sdl/source/cli/config.h b/platform-sdl/source/cli/config.h new file mode 100644 index 0000000..f046007 --- /dev/null +++ b/platform-sdl/source/cli/config.h @@ -0,0 +1,37 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FB_SDL_CLI_CONFIG_H +#define FB_SDL_CLI_CONFIG_H + +#include +#include + +namespace FunkyBoy::SDL { + + typedef struct { + fs::path romPath; + +#if FB_HAS_SOCKETS + bool socketServer; + std::string socketAddress; + int socketPort; +#endif + } CLIConfig; + +} + +#endif //FB_SDL_CLI_CONFIG_H diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 82443c3..a65eb48 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -24,6 +24,11 @@ #include #include #include +#include + +#if FB_HAS_SOCKETS +#include +#endif using namespace FunkyBoy::SDL; @@ -63,6 +68,12 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { cxxopts::Options options(fs::path(argv[0]).filename().string(), "Game Boy emulator"); options.add_options() +#if FB_HAS_SOCKETS + ("server", "Start a server for multiplayer", + cxxopts::value()->default_value("localhost:8020"), "Expected format: :") + ("client", "Connect to a server for multiplayer (address:port)", + cxxopts::value()->default_value("localhost:8020"), "Expected format: :") +#endif ("t,test", "Test whether the application can start correctly") ("h,help", "Print usage") ; @@ -79,6 +90,29 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { return false; } + FunkyBoy::SDL::CLIConfig config; + +#if FB_HAS_SOCKETS + std::regex socketAddressRegex("([a-ZA-Z0-9\\.-_]+):([0-9]+)"); + if (result.count("server")) { + std::smatch matches; + if (!std::regex_search(result["server"].as(), matches, socketAddressRegex)) { + std::cerr << "Server address needs to be in : format!" << std::endl; + return false; + } + config.socketAddress = matches[1].str(); + config.socketPort = std::stoi(matches[2].str()); + } else if (result.count("client")) { + std::smatch matches; + if (!std::regex_search(result["client"].as(), matches, socketAddressRegex)) { + std::cerr << "Client address needs to be in : format!" << std::endl; + return false; + } + config.socketAddress = matches[1].str(); + config.socketPort = std::stoi(matches[2].str()); + } +#endif + window = SDL_CreateWindow( FB_NAME, SDL_WINDOWPOS_UNDEFINED, @@ -100,7 +134,6 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { controllers->setSerial(std::make_shared()); controllers->setDisplay(std::make_shared(renderer, frameBuffer)); - fs::path romPath; if (result.unmatched().empty()) { std::cerr << "No ROM specified as command line argument" << std::endl; @@ -112,22 +145,27 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { NativeUI::selectFiles(window, "Select a Gameboy ROM", romExtensions, false, selectedPaths); - if (selectedPaths.size() > 0) { - romPath = selectedPaths[0]; + if (!selectedPaths.empty()) { + config.romPath = selectedPaths[0]; } } else { - romPath = result.unmatched()[0]; + config.romPath = result.unmatched()[0]; } - if (romPath.empty()) { + if (config.romPath.empty()) { std::cerr << "Empty ROM path specified" << std::endl; return false; } - std::cout << "Loading ROM from " << romPath << "..." << std::endl; - auto status = emulator.loadGame(fs::path(romPath)); + +#if FB_HAS_SOCKETS + +#endif + + std::cout << "Loading ROM from " << config.romPath << "..." << std::endl; + auto status = emulator.loadGame(fs::path(config.romPath)); if (status == CartridgeStatus::Loaded) { - std::cout << "Loaded ROM at " << romPath << std::endl; + std::cout << "Loaded ROM at " << config.romPath << std::endl; - savePath = romPath; + savePath = config.romPath; savePath.replace_extension(".sav"); emulator.savePath = savePath; @@ -140,7 +178,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { SDL_SetWindowTitle(window, title.c_str()); return true; } else { - std::cerr << "Could not load ROM at " << romPath << " (status=" << status << ")" << std::endl; + std::cerr << "Could not load ROM at " << config.romPath << " (status=" << status << ")" << std::endl; return false; } } diff --git a/platform-sdl/source/window/window.h b/platform-sdl/source/window/window.h index 0e562cc..5cf41f1 100644 --- a/platform-sdl/source/window/window.h +++ b/platform-sdl/source/window/window.h @@ -22,6 +22,10 @@ #include #include +#if FB_HAS_SOCKETS +#include +#endif + namespace FunkyBoy::SDL { class Window From 007ba99d251e348d45f07b220a5266187dc65dff Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Fri, 14 May 2021 23:00:34 +0200 Subject: [PATCH 02/15] [WIP] Fix C sockets API check (#25) --- platform-sdl/CMakeLists.txt | 44 +++++++++++-------- platform-sdl/source/sockets/bsd_server.cpp | 5 +++ platform-sdl/source/sockets/bsd_server.h | 8 ++++ .../source/sockets/socket_exception.cpp | 5 +++ .../source/sockets/socket_exception.h | 8 ++++ 5 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 platform-sdl/source/sockets/bsd_server.cpp create mode 100644 platform-sdl/source/sockets/bsd_server.h create mode 100644 platform-sdl/source/sockets/socket_exception.cpp create mode 100644 platform-sdl/source/sockets/socket_exception.h diff --git a/platform-sdl/CMakeLists.txt b/platform-sdl/CMakeLists.txt index 75ada9b..e2cf964 100644 --- a/platform-sdl/CMakeLists.txt +++ b/platform-sdl/CMakeLists.txt @@ -37,6 +37,8 @@ if (OS_MACOS) set(SOURCES ${SOURCES} ${DARWIN_SOURCES}) endif() +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFB_DEBUG") + find_package(SDL2 REQUIRED) if (OS_LINUX) @@ -68,15 +70,33 @@ elseif(OS_LINUX) message(FATAL_ERROR "X11 was not found") endif() +# Check whether we can use sys/socket.h +string(CONFIGURE [[ + #include + #include + #include + + int main() { + sockaddr addr; + sockaddr_in sockaddr; + return 0; + } +]] code @ONLY) +check_cxx_source_compiles("${code}" CAN_COMPILE_C_SOCKET_API_H) +if (CAN_COMPILE_C_SOCKET_API_H) + set(SOURCES ${SOURCES} source/sockets/bsd_server.cpp source/sockets/socket_exception.cpp) + set(HEADERS ${HEADERS} source/sockets/bsd_server.h source/sockets/socket_exception.h) +endif() + if (OS_MACOS) add_executable(fb_sdl MACOSX_BUNDLE ${SOURCES} ${HEADERS}) set_target_properties(fb_sdl PROPERTIES - BUNDLE True - MACOSX_BUNDLE_GUI_IDENTIFIER lu.kremi151.funkyboy.sdl - MACOSX_BUNDLE_BUNDLE_NAME ${FB_NAME} - MACOSX_BUNDLE_BUNDLE_VERSION ${FB_VERSION_MAJOR}.${FB_VERSION_MINOR}.${FB_VERSION_PATCH} - MACOSX_BUNDLE_SHORT_VERSION_STRING ${FB_VERSION} + BUNDLE True + MACOSX_BUNDLE_GUI_IDENTIFIER lu.kremi151.funkyboy.sdl + MACOSX_BUNDLE_BUNDLE_NAME ${FB_NAME} + MACOSX_BUNDLE_BUNDLE_VERSION ${FB_VERSION_MAJOR}.${FB_VERSION_MINOR}.${FB_VERSION_PATCH} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${FB_VERSION} ) else() add_executable(fb_sdl ${SOURCES} ${HEADERS}) @@ -92,19 +112,7 @@ if (OS_MACOS) set_source_files_properties(${DARWIN_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++") endif() -# Check whether we can use sys/socket.h -string(CONFIGURE [[ - #include - - int main() { - sockaddr_in addr; - return 0; - } -]] code @ONLY) -check_cxx_source_compiles("${code}" CAN_COMPILE_WITH_SYS_SOCKET_H) -target_compile_definitions(fb_core PUBLIC -DFB_HAS_SOCKETS=$) - -target_compile_definitions(fb_sdl PRIVATE -DHAS_STD_THIS_THREAD=$) +target_compile_definitions(fb_sdl PUBLIC -DFB_HAS_SOCKETS=$) target_link_libraries(fb_sdl fb_core ${FB_EXTERNAL_LIBS}) diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp new file mode 100644 index 0000000..bc89803 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -0,0 +1,5 @@ +// +// Created by mkremer on 14.05.21. +// + +#include "bsd_server.h" diff --git a/platform-sdl/source/sockets/bsd_server.h b/platform-sdl/source/sockets/bsd_server.h new file mode 100644 index 0000000..5a8ca56 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_server.h @@ -0,0 +1,8 @@ +// +// Created by mkremer on 14.05.21. +// + +#ifndef FB_SDL_BSD_SERVER_H +#define FB_SDL_BSD_SERVER_H + +#endif //FB_SDL_BSD_SERVER_H diff --git a/platform-sdl/source/sockets/socket_exception.cpp b/platform-sdl/source/sockets/socket_exception.cpp new file mode 100644 index 0000000..320087e --- /dev/null +++ b/platform-sdl/source/sockets/socket_exception.cpp @@ -0,0 +1,5 @@ +// +// Created by mkremer on 14.05.21. +// + +#include "socket_exception.h" diff --git a/platform-sdl/source/sockets/socket_exception.h b/platform-sdl/source/sockets/socket_exception.h new file mode 100644 index 0000000..e037483 --- /dev/null +++ b/platform-sdl/source/sockets/socket_exception.h @@ -0,0 +1,8 @@ +// +// Created by mkremer on 14.05.21. +// + +#ifndef FB_SDL_SOCKET_EXCEPTION_H +#define FB_SDL_SOCKET_EXCEPTION_H + +#endif //FB_SDL_SOCKET_EXCEPTION_H From ee452ff65a935603dde3088209f5949525d39900 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 15 May 2021 00:12:47 +0200 Subject: [PATCH 03/15] [WIP] Setup basic socket server --- platform-sdl/source/main.cpp | 11 ++- platform-sdl/source/sockets/bsd_server.cpp | 85 ++++++++++++++++++- platform-sdl/source/sockets/bsd_server.h | 49 +++++++++-- .../source/sockets/socket_exception.cpp | 28 +++++- .../source/sockets/socket_exception.h | 40 +++++++-- platform-sdl/source/window/window.cpp | 18 ++-- platform-sdl/source/window/window.h | 6 +- 7 files changed, 207 insertions(+), 30 deletions(-) diff --git a/platform-sdl/source/main.cpp b/platform-sdl/source/main.cpp index d6b3bca..2a9610f 100644 --- a/platform-sdl/source/main.cpp +++ b/platform-sdl/source/main.cpp @@ -27,8 +27,17 @@ int main(int argc, char **argv) { SDL_Init(SDL_INIT_VIDEO); FunkyBoy::SDL::Window fbWindow(FunkyBoy::GameBoyType::GameBoyDMG); - bool romLoaded = fbWindow.init(argc, argv, FB_GB_DISPLAY_WIDTH * 3, FB_GB_DISPLAY_HEIGHT * 3); + bool romLoaded; int retCode = 0; + try { + romLoaded = fbWindow.init(argc, argv, FB_GB_DISPLAY_WIDTH * 3, FB_GB_DISPLAY_HEIGHT * 3); + } catch (const std::exception &ex) { + std::cerr + << "An error occurred during initialization:" << std::endl + << ex.what() << std::endl; + romLoaded = false; + retCode = 1; + } if (romLoaded) { runGame(fbWindow); diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp index bc89803..2fd004d 100644 --- a/platform-sdl/source/sockets/bsd_server.cpp +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -1,5 +1,84 @@ -// -// Created by mkremer on 14.05.21. -// +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "bsd_server.h" + +#include "socket_exception.h" + +#include +#include + +using namespace FunkyBoy::SDL::Sockets; + +BSDServer::BSDServer(const CLIConfig &config) { + serverFd = socket(AF_INET, SOCK_STREAM, 0); + if (serverFd == 0) { + throw SocketException("Unable to create socket"); + } + /*int opt = 1; + if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + throw SocketException("Unable to attach to port " + std::to_string(config.socketPort)); + }*/ + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(config.socketPort); + if (bind(serverFd, reinterpret_cast(&address), sizeof(address)) < 0) { + throw SocketException("Unable to bind to port " + std::to_string(config.socketPort)); + } + if (listen(serverFd, 3) < 0) { + throw SocketException("Unable to listen on port " + std::to_string(config.socketPort)); + } + serverThread = std::thread([&] { + accept(); + }); +} + +BSDServer::~BSDServer() { +#ifdef FB_DEBUG + std::cout << "Closing socket file descriptor..." << std::endl; +#endif + shutdown(serverFd, 2); + close(serverFd); + serverFd = 0; +#ifdef FB_DEBUG + std::cout << "Socket file descriptor closed, joining server thread..." << std::endl; +#endif + serverThread.join(); +#ifdef FB_DEBUG + std::cout << "Server thread has stopped" << std::endl; +#endif +} + +void BSDServer::accept() { + int addrlen = sizeof(address); + char buffer[16] = {0}; // TODO: Large enough? + while (serverFd) { +#ifdef FB_DEBUG + std::cout << "Accepting on socket..." << std::endl; +#endif + int clientSocket = ::accept(serverFd, reinterpret_cast(&address), + reinterpret_cast(&addrlen)); + if (clientSocket < 0) { + continue; + } + std::cout << "Got connection from " << clientSocket << std::endl; + + size_t bytesRead; + while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) { + // TODO: Transfer bit to serial controller + } + } +} \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_server.h b/platform-sdl/source/sockets/bsd_server.h index 5a8ca56..2b27848 100644 --- a/platform-sdl/source/sockets/bsd_server.h +++ b/platform-sdl/source/sockets/bsd_server.h @@ -1,8 +1,45 @@ -// -// Created by mkremer on 14.05.21. -// +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#ifndef FB_SDL_BSD_SERVER_H -#define FB_SDL_BSD_SERVER_H +#ifndef FB_SDL_SOCKETS_BSD_SERVER_H +#define FB_SDL_SOCKETS_BSD_SERVER_H -#endif //FB_SDL_BSD_SERVER_H +#include +#include +#include +#include + +#include + +namespace FunkyBoy::SDL::Sockets { + + class BSDServer { + private: + int serverFd; + struct sockaddr_in address{}; + std::thread serverThread; + + void accept(); + public: + explicit BSDServer(const CLIConfig &config); + ~BSDServer(); + }; + + typedef std::unique_ptr BSDServerPtr; + +} + +#endif //FB_SDL_SOCKETS_BSD_SERVER_H diff --git a/platform-sdl/source/sockets/socket_exception.cpp b/platform-sdl/source/sockets/socket_exception.cpp index 320087e..0f0b084 100644 --- a/platform-sdl/source/sockets/socket_exception.cpp +++ b/platform-sdl/source/sockets/socket_exception.cpp @@ -1,5 +1,27 @@ -// -// Created by mkremer on 14.05.21. -// +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "socket_exception.h" + +using namespace FunkyBoy::SDL::Sockets; + +SocketException::SocketException(std::string message): message(std::move(message)) +{ +} + +const char* SocketException::what() const noexcept { + return message.c_str(); +} diff --git a/platform-sdl/source/sockets/socket_exception.h b/platform-sdl/source/sockets/socket_exception.h index e037483..1c68c4c 100644 --- a/platform-sdl/source/sockets/socket_exception.h +++ b/platform-sdl/source/sockets/socket_exception.h @@ -1,8 +1,36 @@ -// -// Created by mkremer on 14.05.21. -// +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#ifndef FB_SDL_SOCKET_EXCEPTION_H -#define FB_SDL_SOCKET_EXCEPTION_H +#ifndef FB_SDL_SOCKETS_SOCKET_EXCEPTION_H +#define FB_SDL_SOCKETS_SOCKET_EXCEPTION_H -#endif //FB_SDL_SOCKET_EXCEPTION_H +#include +#include + +namespace FunkyBoy::SDL::Sockets { + + class SocketException: public std::exception { + private: + const std::string message; + public: + SocketException(std::string message); + + const char *what() const noexcept override; + }; + +} + +#endif //FB_SDL_SOCKETS_SOCKET_EXCEPTION_H diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index a65eb48..b06dafa 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -70,7 +70,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { options.add_options() #if FB_HAS_SOCKETS ("server", "Start a server for multiplayer", - cxxopts::value()->default_value("localhost:8020"), "Expected format: :") + cxxopts::value()->default_value("8020")) ("client", "Connect to a server for multiplayer (address:port)", cxxopts::value()->default_value("localhost:8020"), "Expected format: :") #endif @@ -93,21 +93,17 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { FunkyBoy::SDL::CLIConfig config; #if FB_HAS_SOCKETS - std::regex socketAddressRegex("([a-ZA-Z0-9\\.-_]+):([0-9]+)"); if (result.count("server")) { - std::smatch matches; - if (!std::regex_search(result["server"].as(), matches, socketAddressRegex)) { - std::cerr << "Server address needs to be in : format!" << std::endl; - return false; - } - config.socketAddress = matches[1].str(); - config.socketPort = std::stoi(matches[2].str()); + config.socketServer = true; + config.socketPort = result["server"].as(); } else if (result.count("client")) { + std::regex socketAddressRegex("([a-ZA-Z0-9\\.-_]+):([0-9]+)"); std::smatch matches; if (!std::regex_search(result["client"].as(), matches, socketAddressRegex)) { std::cerr << "Client address needs to be in : format!" << std::endl; return false; } + config.socketServer = false; config.socketAddress = matches[1].str(); config.socketPort = std::stoi(matches[2].str()); } @@ -157,7 +153,9 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { } #if FB_HAS_SOCKETS - + if (config.socketServer) { + bsdServer = std::make_unique(config); + } #endif std::cout << "Loading ROM from " << config.romPath << "..." << std::endl; diff --git a/platform-sdl/source/window/window.h b/platform-sdl/source/window/window.h index 5cf41f1..9846623 100644 --- a/platform-sdl/source/window/window.h +++ b/platform-sdl/source/window/window.h @@ -23,7 +23,7 @@ #include #if FB_HAS_SOCKETS -#include +#include #endif namespace FunkyBoy::SDL { @@ -59,6 +59,10 @@ namespace FunkyBoy::SDL { bool btnLeftWasPressed; bool btnRightWasPressed; +#if FB_HAS_SOCKETS + Sockets::BSDServerPtr bsdServer; +#endif + void updateInputs(); void saveState(); From 940d110caaaf6503b46917b8422075e9af59e69b Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 15 May 2021 12:50:23 +0200 Subject: [PATCH 04/15] Add BSD socket client (#25) --- platform-sdl/CMakeLists.txt | 22 +++-- platform-sdl/source/sockets/bsd_client.cpp | 87 +++++++++++++++++++ platform-sdl/source/sockets/bsd_client.h | 41 +++++++++ platform-sdl/source/sockets/bsd_server.cpp | 21 ++++- platform-sdl/source/sockets/bsd_server.h | 9 +- .../source/sockets/socket_interface.h | 33 +++++++ platform-sdl/source/window/window.cpp | 9 +- platform-sdl/source/window/window.h | 4 +- 8 files changed, 212 insertions(+), 14 deletions(-) create mode 100644 platform-sdl/source/sockets/bsd_client.cpp create mode 100644 platform-sdl/source/sockets/bsd_client.h create mode 100644 platform-sdl/source/sockets/socket_interface.h diff --git a/platform-sdl/CMakeLists.txt b/platform-sdl/CMakeLists.txt index e2cf964..a368a5e 100644 --- a/platform-sdl/CMakeLists.txt +++ b/platform-sdl/CMakeLists.txt @@ -75,6 +75,7 @@ string(CONFIGURE [[ #include #include #include + #include int main() { sockaddr addr; @@ -82,10 +83,21 @@ string(CONFIGURE [[ return 0; } ]] code @ONLY) -check_cxx_source_compiles("${code}" CAN_COMPILE_C_SOCKET_API_H) -if (CAN_COMPILE_C_SOCKET_API_H) - set(SOURCES ${SOURCES} source/sockets/bsd_server.cpp source/sockets/socket_exception.cpp) - set(HEADERS ${HEADERS} source/sockets/bsd_server.h source/sockets/socket_exception.h) +check_cxx_source_compiles("${code}" CAN_COMPILE_BSD_SOCKET_API_H) +if (CAN_COMPILE_BSD_SOCKET_API_H) + set(SOURCES + ${SOURCES} + source/sockets/bsd_server.cpp + source/sockets/bsd_client.cpp + source/sockets/socket_exception.cpp + ) + set(HEADERS + ${HEADERS} + source/sockets/socket_interface.h + source/sockets/bsd_server.h + source/sockets/bsd_client.h + source/sockets/socket_exception.h + ) endif() if (OS_MACOS) @@ -112,7 +124,7 @@ if (OS_MACOS) set_source_files_properties(${DARWIN_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++") endif() -target_compile_definitions(fb_sdl PUBLIC -DFB_HAS_SOCKETS=$) +target_compile_definitions(fb_sdl PUBLIC -DFB_HAS_SOCKETS=$) target_link_libraries(fb_sdl fb_core ${FB_EXTERNAL_LIBS}) diff --git a/platform-sdl/source/sockets/bsd_client.cpp b/platform-sdl/source/sockets/bsd_client.cpp new file mode 100644 index 0000000..eff83b6 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_client.cpp @@ -0,0 +1,87 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bsd_client.h" + +#include +#include +#include +#include +#include "socket_exception.h" + +using namespace FunkyBoy::SDL::Sockets; + +BSDClient::BSDClient(const CLIConfig &config) { + clientFd = socket(AF_INET, SOCK_STREAM, 0); + if (clientFd < 0) { + throw SocketException("Unable to create socket"); + } + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(config.socketPort); + // TODO: Support domains + if (inet_pton(AF_INET, config.socketAddress, &serverAddress.sin_addr) <= 0) { + throw SocketException("Invalid address or address not supported: " + std::string(config.socketAddress)); + } + if (connect(clientFd, reinterpret_cast(&serverAddress), sizeof(serverAddress)) < 0) { + throw SocketException("Connection failed"); + } + + char buffer[8] = {0}; + size_t bytesRead; + + // Send some magic bytes to initiate connection + buffer[0] = 0x42; + buffer[1] = 0x18; + buffer[2] = 0x69; + buffer[3] = 0x06; + buffer[4] = 0x55; + send(clientFd, buffer, 5, 0); + + bytesRead = read(clientFd, buffer, sizeof(buffer)); + if (bytesRead != 5 || buffer[4] != 0x42 || buffer[3] != 0x18 || buffer[2] != 0x69 || buffer[1] != 0x06 || buffer[0] != 0x55) { + throw SocketException("Connection cannot be trusted"); + } + + std::cout << "Connection is trusted" << std::endl; + + clientThread = std::thread([&] { + run(); + }); +} + +BSDClient::~BSDClient() { +#ifdef FB_DEBUG + std::cout << "Closing socket file descriptor..." << std::endl; +#endif + shutdown(clientFd, 2); + close(clientFd); + clientFd = 0; +#ifdef FB_DEBUG + std::cout << "Socket file descriptor closed, joining client thread..." << std::endl; +#endif + clientThread.join(); +#ifdef FB_DEBUG + std::cout << "Client thread has stopped" << std::endl; +#endif +} + +void BSDClient::run() { + char buffer[16] = {0}; + size_t bytesRead; + while (clientFd > 0) { + // TODO: Handle serial bits + } +} \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_client.h b/platform-sdl/source/sockets/bsd_client.h new file mode 100644 index 0000000..1e28d48 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_client.h @@ -0,0 +1,41 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FB_SDL_SOCKETS_BSD_CLIENT_H +#define FB_SDL_SOCKETS_BSD_CLIENT_H + +#include +#include +#include +#include "socket_interface.h" + +namespace FunkyBoy::SDL::Sockets { + + class BSDClient: public SocketInterface { + private: + int clientFd; + struct sockaddr_in serverAddress{}; + std::thread clientThread; + + void run(); + public: + explicit BSDClient(const CLIConfig &config); + ~BSDClient() override; + }; + +} + +#endif //FB_SDL_SOCKETS_BSD_CLIENT_H diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp index 2fd004d..ebc9485 100644 --- a/platform-sdl/source/sockets/bsd_server.cpp +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -64,7 +64,7 @@ BSDServer::~BSDServer() { void BSDServer::accept() { int addrlen = sizeof(address); - char buffer[16] = {0}; // TODO: Large enough? + char buffer[16] = {0}; while (serverFd) { #ifdef FB_DEBUG std::cout << "Accepting on socket..." << std::endl; @@ -77,6 +77,25 @@ void BSDServer::accept() { std::cout << "Got connection from " << clientSocket << std::endl; size_t bytesRead; + + // Receive and check initial magic bytes + bytesRead = read(clientSocket, buffer, sizeof(buffer)); + if (bytesRead != 5 || buffer[0] != 0x42 || buffer[1] != 0x18 || buffer[2] != 0x69 || buffer[3] != 0x06 || buffer[4] != 0x55) { + std::cerr << "Connection from " << clientSocket << " cannot be trusted" << std::endl; + shutdown(clientSocket, 2); + close(clientSocket); + continue; + } + // Send reversed magic bytes + buffer[4] = 0x42; + buffer[3] = 0x18; + buffer[2] = 0x69; + buffer[1] = 0x06; + buffer[0] = 0x55; + send(clientSocket, buffer, 5, 0); + + std::cout << "Connection from " << clientSocket << " is trusted" << std::endl; + while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) { // TODO: Transfer bit to serial controller } diff --git a/platform-sdl/source/sockets/bsd_server.h b/platform-sdl/source/sockets/bsd_server.h index 2b27848..f9c3079 100644 --- a/platform-sdl/source/sockets/bsd_server.h +++ b/platform-sdl/source/sockets/bsd_server.h @@ -20,13 +20,14 @@ #include #include #include -#include #include +#include "socket_interface.h" + namespace FunkyBoy::SDL::Sockets { - class BSDServer { + class BSDServer: public SocketInterface { private: int serverFd; struct sockaddr_in address{}; @@ -35,11 +36,9 @@ namespace FunkyBoy::SDL::Sockets { void accept(); public: explicit BSDServer(const CLIConfig &config); - ~BSDServer(); + ~BSDServer() override; }; - typedef std::unique_ptr BSDServerPtr; - } #endif //FB_SDL_SOCKETS_BSD_SERVER_H diff --git a/platform-sdl/source/sockets/socket_interface.h b/platform-sdl/source/sockets/socket_interface.h new file mode 100644 index 0000000..c1500a6 --- /dev/null +++ b/platform-sdl/source/sockets/socket_interface.h @@ -0,0 +1,33 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FB_SDL_SOCKETS_SOCKET_INTERFACE_H +#define FB_SDL_SOCKETS_SOCKET_INTERFACE_H + +#include + +namespace FunkyBoy::SDL::Sockets { + + class SocketInterface { + public: + virtual ~SocketInterface() = default; + }; + + typedef std::unique_ptr SocketInterfacePtr; + +} + +#endif //FB_SDL_SOCKETS_SOCKET_INTERFACE_H diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index b06dafa..5b9bc9e 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -30,6 +30,11 @@ #include #endif +#if FB_HAS_SOCKETS +#include +#include +#endif + using namespace FunkyBoy::SDL; Window::Window(FunkyBoy::GameBoyType gbType) @@ -154,7 +159,9 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { #if FB_HAS_SOCKETS if (config.socketServer) { - bsdServer = std::make_unique(config); + socketInterface = std::make_unique(config); + } else if (config.socketAddress != nullptr) { + socketInterface = std::make_unique(config); } #endif diff --git a/platform-sdl/source/window/window.h b/platform-sdl/source/window/window.h index 9846623..6c57f0d 100644 --- a/platform-sdl/source/window/window.h +++ b/platform-sdl/source/window/window.h @@ -23,7 +23,7 @@ #include #if FB_HAS_SOCKETS -#include +#include #endif namespace FunkyBoy::SDL { @@ -60,7 +60,7 @@ namespace FunkyBoy::SDL { bool btnRightWasPressed; #if FB_HAS_SOCKETS - Sockets::BSDServerPtr bsdServer; + Sockets::SocketInterfacePtr socketInterface; #endif void updateInputs(); From 8eae599c3521f9fa420e510fe363e3ae5c3fe1d3 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 15 May 2021 12:53:46 +0200 Subject: [PATCH 05/15] Default initialize CLI config (#25) --- platform-sdl/source/window/window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 5b9bc9e..4e79d5d 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -95,7 +95,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { return false; } - FunkyBoy::SDL::CLIConfig config; + FunkyBoy::SDL::CLIConfig config{}; #if FB_HAS_SOCKETS if (result.count("server")) { @@ -160,7 +160,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { #if FB_HAS_SOCKETS if (config.socketServer) { socketInterface = std::make_unique(config); - } else if (config.socketAddress != nullptr) { + } else if (!config.socketAddress.empty()) { socketInterface = std::make_unique(config); } #endif From 9245cb378d359fea013b398b327a254c1d28d7b4 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 15 May 2021 13:29:03 +0200 Subject: [PATCH 06/15] [WIP] Base serial implementation in the core (#25) --- core/CMakeLists.txt | 1 + core/source/controllers/serial.h | 3 +- core/source/controllers/serial_null.cpp | 2 +- core/source/controllers/serial_null.h | 2 +- core/source/emulator/cpu.cpp | 8 +---- core/source/emulator/cpu.h | 9 +----- core/source/emulator/io_registers.cpp | 13 ++++++++ core/source/emulator/io_registers.h | 13 ++++++++ core/source/memory/memory.cpp | 14 ++++++-- core/source/util/interrupt_type.h | 32 +++++++++++++++++++ .../source/controllers/serial_sdl.cpp | 12 +++++-- platform-sdl/source/controllers/serial_sdl.h | 14 +++++++- .../source/sockets/socket_interface.h | 6 +++- platform-sdl/source/window/window.cpp | 14 +++++--- 14 files changed, 113 insertions(+), 30 deletions(-) create mode 100644 core/source/util/interrupt_type.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index ea21daf..4cdb959 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -102,6 +102,7 @@ set(HEADERS source/util/frame_executor.h source/util/stream_utils.h source/util/membuf.h + source/util/interrupt_type.h source/palette/dmg_palette.h source/exception/state_exception.h source/exception/read_exception.h diff --git a/core/source/controllers/serial.h b/core/source/controllers/serial.h index 5501679..3ae0b23 100644 --- a/core/source/controllers/serial.h +++ b/core/source/controllers/serial.h @@ -19,6 +19,7 @@ #include #include +#include namespace FunkyBoy::Controller { @@ -26,7 +27,7 @@ namespace FunkyBoy::Controller { public: virtual ~SerialController() = default; - virtual void sendByte(u8 data) = 0; + virtual void sendBit(u8 data, std::function callback) = 0; }; typedef std::shared_ptr SerialControllerPtr; diff --git a/core/source/controllers/serial_null.cpp b/core/source/controllers/serial_null.cpp index 25f1733..1e40f5a 100644 --- a/core/source/controllers/serial_null.cpp +++ b/core/source/controllers/serial_null.cpp @@ -18,6 +18,6 @@ using namespace FunkyBoy::Controller; -void SerialControllerVoid::sendByte(FunkyBoy::u8 data) { +void SerialControllerVoid::sendBit(FunkyBoy::u8 data, std::function callback) { // Do nothing } \ No newline at end of file diff --git a/core/source/controllers/serial_null.h b/core/source/controllers/serial_null.h index c1d7337..3425436 100644 --- a/core/source/controllers/serial_null.h +++ b/core/source/controllers/serial_null.h @@ -23,7 +23,7 @@ namespace FunkyBoy::Controller { class SerialControllerVoid: public SerialController { public: - void sendByte(u8 data) override; + void sendBit(u8 data, std::function callback) override; }; } diff --git a/core/source/emulator/cpu.cpp b/core/source/emulator/cpu.cpp index bfbc63b..99b4091 100644 --- a/core/source/emulator/cpu.cpp +++ b/core/source/emulator/cpu.cpp @@ -225,10 +225,6 @@ inline memory_address getInterruptStartAddress(InterruptType type) { return 0x0040 + (static_cast(type) * 0x8); } -inline u8 getInterruptBitMask(InterruptType type) { - return 1u << static_cast(type); -} - void CPU::doJoypad() { u8_fast oldP1 = ioRegisters.getP1() & 0b00001111u; u8_fast newP1 = ioRegisters.updateJoypad() & 0b00001111u; @@ -351,9 +347,7 @@ void CPU::doTimers(Memory &memory, u8 clocks) { } void CPU::requestInterrupt(InterruptType type) { - //fprintf(stdout, "#req int %d\n", type); - u8 &_if = ioRegisters.getIF(); - _if |= getInterruptBitMask(type); + ioRegisters.requestInterrupt(type); } void CPU::setProgramCounter(u16 offset) { diff --git a/core/source/emulator/cpu.h b/core/source/emulator/cpu.h index bef1684..6ce1581 100644 --- a/core/source/emulator/cpu.h +++ b/core/source/emulator/cpu.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -34,14 +35,6 @@ namespace FunkyBoy { - enum InterruptType { - VBLANK = 0, - LCD_STAT = 1, - TIMER = 2, - SERIAL = 3, - JOYPAD = 4 - }; - class CPU { private: io_registers ioRegisters; diff --git a/core/source/emulator/io_registers.cpp b/core/source/emulator/io_registers.cpp index 68923f6..ee0d992 100644 --- a/core/source/emulator/io_registers.cpp +++ b/core/source/emulator/io_registers.cpp @@ -18,6 +18,14 @@ #include #include +namespace FunkyBoy { + + inline u8 getInterruptBitMask(InterruptType type) { + return 1u << static_cast(type); + } + +} + using namespace FunkyBoy; #define FB_HW_IO_BYTES 128 @@ -173,6 +181,11 @@ u8_fast io_registers::updateJoypad() { return val; } +void io_registers::requestInterrupt(InterruptType type) { + u8 &_if = getIF(); + _if |= getInterruptBitMask(type); +} + void io_registers::serialize(std::ostream &ostream) const { ostream.write(reinterpret_cast(hwIO), FB_HW_IO_BYTES); ostream.put(*inputsDPad & 0xffu); diff --git a/core/source/emulator/io_registers.h b/core/source/emulator/io_registers.h index c29d8c9..d6f9d7f 100644 --- a/core/source/emulator/io_registers.h +++ b/core/source/emulator/io_registers.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -47,6 +48,8 @@ #define FB_REG_IE 0xFFFF #define __FB_REG_OFFSET_P1 (FB_REG_P1 - 0xFF00) +#define __FB_REG_OFFSET_SB (FB_REG_SB - 0xFF00) +#define __FB_REG_OFFSET_SC (FB_REG_SC - 0xFF00) #define __FB_REG_OFFSET_DIV (FB_REG_DIV - 0xFF00) #define __FB_REG_OFFSET_TIMA (FB_REG_TIMA - 0xFF00) #define __FB_REG_OFFSET_TMA (FB_REG_TMA - 0xFF00) @@ -100,10 +103,20 @@ namespace FunkyBoy { u8_fast updateJoypad(); + void requestInterrupt(InterruptType type); + inline u8 &getP1() { return *(hwIO + __FB_REG_OFFSET_P1); } + inline u8 &getSB() { + return *(hwIO + __FB_REG_OFFSET_SB); + } + + inline u8 &getSC() { + return *(hwIO + __FB_REG_OFFSET_SC); + } + inline u8 &getTIMA() { return *(hwIO + __FB_REG_OFFSET_TIMA); } diff --git a/core/source/memory/memory.cpp b/core/source/memory/memory.cpp index 8bbe9a9..16a0d38 100644 --- a/core/source/memory/memory.cpp +++ b/core/source/memory/memory.cpp @@ -471,8 +471,18 @@ void Memory::write8BitsTo(memory_address offset, u8 val) { // IO registers if (offset == FB_REG_SC) { - if (val == 0x81) { - controllers->getSerial()->sendByte(read8BitsAt(FB_REG_SB)); + if (val & 0b10000000) { + controllers->getSerial()->sendBit(read8BitsAt(FB_REG_SB), [&](u8_fast data) { + std::cout << "Received data: " << (data & 0xFFFF) << std::endl; + + u8 &sb = ioRegisters.getSB(); + sb = (sb << 1) | (data & 0b1); + + u8 &sc = ioRegisters.getSC(); + sc &= 0b01111111; + + ioRegisters.requestInterrupt(InterruptType::SERIAL); + }); } } else if (offset == FB_REG_DMA) { dmaStarted = true; diff --git a/core/source/util/interrupt_type.h b/core/source/util/interrupt_type.h new file mode 100644 index 0000000..c4806cf --- /dev/null +++ b/core/source/util/interrupt_type.h @@ -0,0 +1,32 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FB_CORE_INTERRUPT_TYPE_H +#define FB_CORE_INTERRUPT_TYPE_H + +namespace FunkyBoy { + + enum InterruptType { + VBLANK = 0, + LCD_STAT = 1, + TIMER = 2, + SERIAL = 3, + JOYPAD = 4 + }; + +} + +#endif //FB_CORE_INTERRUPT_TYPE_H diff --git a/platform-sdl/source/controllers/serial_sdl.cpp b/platform-sdl/source/controllers/serial_sdl.cpp index dfa25ce..5d2eafa 100644 --- a/platform-sdl/source/controllers/serial_sdl.cpp +++ b/platform-sdl/source/controllers/serial_sdl.cpp @@ -20,7 +20,13 @@ using namespace FunkyBoy::Controller; -void SerialControllerSDL::sendByte(FunkyBoy::u8 data) { - // TODO: This is only temporary so that I see whether my emulator is doing something, to be removed - std::cout << data; +#if FB_HAS_SOCKETS +SerialControllerSDL::SerialControllerSDL(SDL::Sockets::SocketInterfacePtr socketInterface): socketInterface(std::move(socketInterface)) { +} +#endif + +void SerialControllerSDL::sendBit(FunkyBoy::u8 data, std::function callback) { +#if FB_HAS_SOCKETS + socketInterface->transferBit(data, callback); +#endif } \ No newline at end of file diff --git a/platform-sdl/source/controllers/serial_sdl.h b/platform-sdl/source/controllers/serial_sdl.h index e861972..f29a132 100644 --- a/platform-sdl/source/controllers/serial_sdl.h +++ b/platform-sdl/source/controllers/serial_sdl.h @@ -19,11 +19,23 @@ #include +#if FB_HAS_SOCKETS +#include +#endif + namespace FunkyBoy::Controller { class SerialControllerSDL: public SerialController { + private: +#if FB_HAS_SOCKETS + SDL::Sockets::SocketInterfacePtr socketInterface; +#endif public: - void sendByte(u8 data) override; +#if FB_HAS_SOCKETS + explicit SerialControllerSDL(SDL::Sockets::SocketInterfacePtr socketInterface); +#endif + + void sendBit(u8 data, std::function callback) override; }; } diff --git a/platform-sdl/source/sockets/socket_interface.h b/platform-sdl/source/sockets/socket_interface.h index c1500a6..2751e9f 100644 --- a/platform-sdl/source/sockets/socket_interface.h +++ b/platform-sdl/source/sockets/socket_interface.h @@ -18,15 +18,19 @@ #define FB_SDL_SOCKETS_SOCKET_INTERFACE_H #include +#include +#include namespace FunkyBoy::SDL::Sockets { class SocketInterface { public: virtual ~SocketInterface() = default; + + virtual void transferBit(FunkyBoy::u8_fast bit, std::function callback) = 0; }; - typedef std::unique_ptr SocketInterfacePtr; + typedef std::shared_ptr SocketInterfacePtr; } diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 4e79d5d..7c5c35b 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -132,9 +132,6 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { SDL_RenderSetLogicalSize(renderer, FB_GB_DISPLAY_WIDTH, FB_GB_DISPLAY_HEIGHT); - controllers->setSerial(std::make_shared()); - controllers->setDisplay(std::make_shared(renderer, frameBuffer)); - if (result.unmatched().empty()) { std::cerr << "No ROM specified as command line argument" << std::endl; @@ -159,12 +156,19 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { #if FB_HAS_SOCKETS if (config.socketServer) { - socketInterface = std::make_unique(config); + socketInterface = std::make_shared(config); } else if (!config.socketAddress.empty()) { - socketInterface = std::make_unique(config); + socketInterface = std::make_shared(config); } #endif + controllers->setSerial(std::make_shared( +#if FB_HAS_SOCKETS + socketInterface +#endif + )); + controllers->setDisplay(std::make_shared(renderer, frameBuffer)); + std::cout << "Loading ROM from " << config.romPath << "..." << std::endl; auto status = emulator.loadGame(fs::path(config.romPath)); if (status == CartridgeStatus::Loaded) { From 6bccdf808ed35ea0d0df7f24b23a82e83dcc9331 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Mon, 17 May 2021 22:28:18 +0200 Subject: [PATCH 07/15] [WIP] Refactor common BSD code into single base class (#25) --- core/source/controllers/serial.h | 3 +- core/source/controllers/serial_null.cpp | 6 +- core/source/controllers/serial_null.h | 3 +- core/source/memory/memory.cpp | 24 ++++---- platform-sdl/CMakeLists.txt | 2 + .../source/controllers/serial_sdl.cpp | 8 ++- platform-sdl/source/controllers/serial_sdl.h | 5 +- platform-sdl/source/sockets/bsd_client.cpp | 42 ++++---------- platform-sdl/source/sockets/bsd_client.h | 17 ++---- platform-sdl/source/sockets/bsd_common.cpp | 57 +++++++++++++++++++ platform-sdl/source/sockets/bsd_common.h | 50 ++++++++++++++++ platform-sdl/source/sockets/bsd_server.cpp | 38 ++++--------- platform-sdl/source/sockets/bsd_server.h | 22 ++----- .../source/sockets/socket_interface.h | 3 + platform-sdl/source/window/window.cpp | 7 ++- 15 files changed, 180 insertions(+), 107 deletions(-) create mode 100644 platform-sdl/source/sockets/bsd_common.cpp create mode 100644 platform-sdl/source/sockets/bsd_common.h diff --git a/core/source/controllers/serial.h b/core/source/controllers/serial.h index 3ae0b23..b73a516 100644 --- a/core/source/controllers/serial.h +++ b/core/source/controllers/serial.h @@ -27,7 +27,8 @@ namespace FunkyBoy::Controller { public: virtual ~SerialController() = default; - virtual void sendBit(u8 data, std::function callback) = 0; + virtual void setup(std::function bitReceived) = 0; + virtual void sendBit(u8 data) = 0; }; typedef std::shared_ptr SerialControllerPtr; diff --git a/core/source/controllers/serial_null.cpp b/core/source/controllers/serial_null.cpp index 1e40f5a..1f09717 100644 --- a/core/source/controllers/serial_null.cpp +++ b/core/source/controllers/serial_null.cpp @@ -18,6 +18,10 @@ using namespace FunkyBoy::Controller; -void SerialControllerVoid::sendBit(FunkyBoy::u8 data, std::function callback) { +void SerialControllerVoid::setup(std::function bitReceived) { + // Do nothing +} + +void SerialControllerVoid::sendBit(FunkyBoy::u8 data) { // Do nothing } \ No newline at end of file diff --git a/core/source/controllers/serial_null.h b/core/source/controllers/serial_null.h index 3425436..dbd2db9 100644 --- a/core/source/controllers/serial_null.h +++ b/core/source/controllers/serial_null.h @@ -23,7 +23,8 @@ namespace FunkyBoy::Controller { class SerialControllerVoid: public SerialController { public: - void sendBit(u8 data, std::function callback) override; + void setup(std::function bitReceived) override; + void sendBit(u8 data) override; }; } diff --git a/core/source/memory/memory.cpp b/core/source/memory/memory.cpp index 16a0d38..8bff24c 100644 --- a/core/source/memory/memory.cpp +++ b/core/source/memory/memory.cpp @@ -91,6 +91,18 @@ namespace FunkyBoy::Util { } void Memory::loadROM(std::istream &stream, bool strictSizeCheck) { + controllers->getSerial()->setup([&](u8_fast data) { + std::cout << "Received data: " << (data & 0xFFFF) << std::endl; + + u8 &sb = ioRegisters.getSB(); + sb = (sb << 1) | (data & 0b1); + + u8 &sc = ioRegisters.getSC(); + sc &= 0b01111111; + + ioRegisters.requestInterrupt(InterruptType::SERIAL); + }); + if (!stream.good()) { #ifdef FB_DEBUG fprintf(stderr, "Stream is not readable\n"); @@ -472,17 +484,7 @@ void Memory::write8BitsTo(memory_address offset, u8 val) { if (offset == FB_REG_SC) { if (val & 0b10000000) { - controllers->getSerial()->sendBit(read8BitsAt(FB_REG_SB), [&](u8_fast data) { - std::cout << "Received data: " << (data & 0xFFFF) << std::endl; - - u8 &sb = ioRegisters.getSB(); - sb = (sb << 1) | (data & 0b1); - - u8 &sc = ioRegisters.getSC(); - sc &= 0b01111111; - - ioRegisters.requestInterrupt(InterruptType::SERIAL); - }); + controllers->getSerial()->sendBit(read8BitsAt(FB_REG_SB)); } } else if (offset == FB_REG_DMA) { dmaStarted = true; diff --git a/platform-sdl/CMakeLists.txt b/platform-sdl/CMakeLists.txt index a368a5e..ae535d6 100644 --- a/platform-sdl/CMakeLists.txt +++ b/platform-sdl/CMakeLists.txt @@ -87,6 +87,7 @@ check_cxx_source_compiles("${code}" CAN_COMPILE_BSD_SOCKET_API_H) if (CAN_COMPILE_BSD_SOCKET_API_H) set(SOURCES ${SOURCES} + source/sockets/bsd_common.cpp source/sockets/bsd_server.cpp source/sockets/bsd_client.cpp source/sockets/socket_exception.cpp @@ -94,6 +95,7 @@ if (CAN_COMPILE_BSD_SOCKET_API_H) set(HEADERS ${HEADERS} source/sockets/socket_interface.h + source/sockets/bsd_common.h source/sockets/bsd_server.h source/sockets/bsd_client.h source/sockets/socket_exception.h diff --git a/platform-sdl/source/controllers/serial_sdl.cpp b/platform-sdl/source/controllers/serial_sdl.cpp index 5d2eafa..cf886cd 100644 --- a/platform-sdl/source/controllers/serial_sdl.cpp +++ b/platform-sdl/source/controllers/serial_sdl.cpp @@ -25,8 +25,12 @@ SerialControllerSDL::SerialControllerSDL(SDL::Sockets::SocketInterfacePtr socket } #endif -void SerialControllerSDL::sendBit(FunkyBoy::u8 data, std::function callback) { +void SerialControllerSDL::setup(std::function bitReceivedCallback) { + this->bitReceived = bitReceivedCallback; +} + +void SerialControllerSDL::sendBit(FunkyBoy::u8 data) { #if FB_HAS_SOCKETS - socketInterface->transferBit(data, callback); + socketInterface->transferBit(data, bitReceived); #endif } \ No newline at end of file diff --git a/platform-sdl/source/controllers/serial_sdl.h b/platform-sdl/source/controllers/serial_sdl.h index f29a132..dfc4806 100644 --- a/platform-sdl/source/controllers/serial_sdl.h +++ b/platform-sdl/source/controllers/serial_sdl.h @@ -27,6 +27,8 @@ namespace FunkyBoy::Controller { class SerialControllerSDL: public SerialController { private: + std::function bitReceived; + #if FB_HAS_SOCKETS SDL::Sockets::SocketInterfacePtr socketInterface; #endif @@ -35,7 +37,8 @@ namespace FunkyBoy::Controller { explicit SerialControllerSDL(SDL::Sockets::SocketInterfacePtr socketInterface); #endif - void sendBit(u8 data, std::function callback) override; + void setup(std::function bitReceived) override; + void sendBit(u8 data) override; }; } diff --git a/platform-sdl/source/sockets/bsd_client.cpp b/platform-sdl/source/sockets/bsd_client.cpp index eff83b6..fe0cd15 100644 --- a/platform-sdl/source/sockets/bsd_client.cpp +++ b/platform-sdl/source/sockets/bsd_client.cpp @@ -24,18 +24,18 @@ using namespace FunkyBoy::SDL::Sockets; -BSDClient::BSDClient(const CLIConfig &config) { - clientFd = socket(AF_INET, SOCK_STREAM, 0); - if (clientFd < 0) { +void BSDClient::setupSocket(const CLIConfig &config) { + socketFd = socket(AF_INET, SOCK_STREAM, 0); + if (socketFd < 0) { throw SocketException("Unable to create socket"); } - serverAddress.sin_family = AF_INET; - serverAddress.sin_port = htons(config.socketPort); + address.sin_family = AF_INET; + address.sin_port = htons(config.socketPort); // TODO: Support domains - if (inet_pton(AF_INET, config.socketAddress, &serverAddress.sin_addr) <= 0) { + if (inet_pton(AF_INET, config.socketAddress, &address.sin_addr) <= 0) { throw SocketException("Invalid address or address not supported: " + std::string(config.socketAddress)); } - if (connect(clientFd, reinterpret_cast(&serverAddress), sizeof(serverAddress)) < 0) { + if (connect(socketFd, reinterpret_cast(&address), sizeof(address)) < 0) { throw SocketException("Connection failed"); } @@ -48,40 +48,20 @@ BSDClient::BSDClient(const CLIConfig &config) { buffer[2] = 0x69; buffer[3] = 0x06; buffer[4] = 0x55; - send(clientFd, buffer, 5, 0); + send(socketFd, buffer, 5, 0); - bytesRead = read(clientFd, buffer, sizeof(buffer)); + bytesRead = read(socketFd, buffer, sizeof(buffer)); if (bytesRead != 5 || buffer[4] != 0x42 || buffer[3] != 0x18 || buffer[2] != 0x69 || buffer[1] != 0x06 || buffer[0] != 0x55) { throw SocketException("Connection cannot be trusted"); } std::cout << "Connection is trusted" << std::endl; - - clientThread = std::thread([&] { - run(); - }); -} - -BSDClient::~BSDClient() { -#ifdef FB_DEBUG - std::cout << "Closing socket file descriptor..." << std::endl; -#endif - shutdown(clientFd, 2); - close(clientFd); - clientFd = 0; -#ifdef FB_DEBUG - std::cout << "Socket file descriptor closed, joining client thread..." << std::endl; -#endif - clientThread.join(); -#ifdef FB_DEBUG - std::cout << "Client thread has stopped" << std::endl; -#endif } -void BSDClient::run() { +void BSDClient::threadMain() { char buffer[16] = {0}; size_t bytesRead; - while (clientFd > 0) { + while (socketFd > 0) { // TODO: Handle serial bits } } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_client.h b/platform-sdl/source/sockets/bsd_client.h index 1e28d48..d88cde0 100644 --- a/platform-sdl/source/sockets/bsd_client.h +++ b/platform-sdl/source/sockets/bsd_client.h @@ -19,21 +19,14 @@ #include #include -#include -#include "socket_interface.h" +#include "bsd_common.h" namespace FunkyBoy::SDL::Sockets { - class BSDClient: public SocketInterface { - private: - int clientFd; - struct sockaddr_in serverAddress{}; - std::thread clientThread; - - void run(); - public: - explicit BSDClient(const CLIConfig &config); - ~BSDClient() override; + class BSDClient: public BSDSocketInterface { + protected: + void setupSocket(const CLIConfig &config) override; + void threadMain() override; }; } diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp new file mode 100644 index 0000000..4c54e06 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -0,0 +1,57 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bsd_common.h" + +#include +#include + +using namespace FunkyBoy::SDL::Sockets; + +BSDSocketInterface::BSDSocketInterface() + : socketFd(0) +{ +} + +BSDSocketInterface::~BSDSocketInterface() { + if (thread.joinable()) { +#ifdef FB_DEBUG + std::cout << "Closing socket file descriptor..." << std::endl; +#endif + shutdown(socketFd, 2); + close(socketFd); + socketFd = 0; +#ifdef FB_DEBUG + std::cout << "Socket file descriptor closed, joining server thread..." << std::endl; +#endif + thread.join(); +#ifdef FB_DEBUG + std::cout << "Server thread has stopped" << std::endl; +#endif + } +} + +void BSDSocketInterface::init(const CLIConfig &config) { + setupSocket(config); + thread = std::thread([&] { + threadMain(); + }); +} + +void BSDSocketInterface::transferBit(FunkyBoy::u8_fast bit, std::function callback) { + std::lock_guard lock(mutex); + // TODO: queue.push(bit); +} \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_common.h b/platform-sdl/source/sockets/bsd_common.h new file mode 100644 index 0000000..253e122 --- /dev/null +++ b/platform-sdl/source/sockets/bsd_common.h @@ -0,0 +1,50 @@ +/** + * Copyright 2021 Michel Kremer (kremi151) + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FB_SDL_SOCKETS_BSD_COMMON_H +#define FB_SDL_SOCKETS_BSD_COMMON_H + +#include "socket_interface.h" + +#include +#include +#include + +namespace FunkyBoy::SDL::Sockets { + + class BSDSocketInterface : public SocketInterface { + private: + std::thread thread; + + protected: + std::mutex mutex; + int socketFd; + struct sockaddr_in address{}; + + virtual void threadMain() = 0; + virtual void setupSocket(const CLIConfig &config) = 0; + + public: + BSDSocketInterface(); + ~BSDSocketInterface() override; + + void init(const CLIConfig &config) final; + void transferBit(FunkyBoy::u8_fast bit, std::function callback) final; + }; + +} + +#endif //FB_SDL_SOCKETS_BSD_COMMON_H diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp index ebc9485..dc969ea 100644 --- a/platform-sdl/source/sockets/bsd_server.cpp +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -18,58 +18,40 @@ #include "socket_exception.h" +#include #include #include using namespace FunkyBoy::SDL::Sockets; -BSDServer::BSDServer(const CLIConfig &config) { - serverFd = socket(AF_INET, SOCK_STREAM, 0); - if (serverFd == 0) { +void BSDServer::setupSocket(const CLIConfig &config) { + socketFd = socket(AF_INET, SOCK_STREAM, 0); + if (socketFd == 0) { throw SocketException("Unable to create socket"); } /*int opt = 1; - if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + if (setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { throw SocketException("Unable to attach to port " + std::to_string(config.socketPort)); }*/ address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(config.socketPort); - if (bind(serverFd, reinterpret_cast(&address), sizeof(address)) < 0) { + if (bind(socketFd, reinterpret_cast(&address), sizeof(address)) < 0) { throw SocketException("Unable to bind to port " + std::to_string(config.socketPort)); } - if (listen(serverFd, 3) < 0) { + if (listen(socketFd, 3) < 0) { throw SocketException("Unable to listen on port " + std::to_string(config.socketPort)); } - serverThread = std::thread([&] { - accept(); - }); } -BSDServer::~BSDServer() { -#ifdef FB_DEBUG - std::cout << "Closing socket file descriptor..." << std::endl; -#endif - shutdown(serverFd, 2); - close(serverFd); - serverFd = 0; -#ifdef FB_DEBUG - std::cout << "Socket file descriptor closed, joining server thread..." << std::endl; -#endif - serverThread.join(); -#ifdef FB_DEBUG - std::cout << "Server thread has stopped" << std::endl; -#endif -} - -void BSDServer::accept() { +void BSDServer::threadMain() { int addrlen = sizeof(address); char buffer[16] = {0}; - while (serverFd) { + while (socketFd > 0) { #ifdef FB_DEBUG std::cout << "Accepting on socket..." << std::endl; #endif - int clientSocket = ::accept(serverFd, reinterpret_cast(&address), + int clientSocket = ::accept(socketFd, reinterpret_cast(&address), reinterpret_cast(&addrlen)); if (clientSocket < 0) { continue; diff --git a/platform-sdl/source/sockets/bsd_server.h b/platform-sdl/source/sockets/bsd_server.h index f9c3079..6c4da28 100644 --- a/platform-sdl/source/sockets/bsd_server.h +++ b/platform-sdl/source/sockets/bsd_server.h @@ -17,26 +17,14 @@ #ifndef FB_SDL_SOCKETS_BSD_SERVER_H #define FB_SDL_SOCKETS_BSD_SERVER_H -#include -#include -#include - -#include - -#include "socket_interface.h" +#include "bsd_common.h" namespace FunkyBoy::SDL::Sockets { - class BSDServer: public SocketInterface { - private: - int serverFd; - struct sockaddr_in address{}; - std::thread serverThread; - - void accept(); - public: - explicit BSDServer(const CLIConfig &config); - ~BSDServer() override; + class BSDServer: public BSDSocketInterface { + protected: + void setupSocket(const CLIConfig &config) override; + void threadMain() override; }; } diff --git a/platform-sdl/source/sockets/socket_interface.h b/platform-sdl/source/sockets/socket_interface.h index 2751e9f..15a172d 100644 --- a/platform-sdl/source/sockets/socket_interface.h +++ b/platform-sdl/source/sockets/socket_interface.h @@ -21,12 +21,15 @@ #include #include +#include + namespace FunkyBoy::SDL::Sockets { class SocketInterface { public: virtual ~SocketInterface() = default; + virtual void init(const CLIConfig &config) = 0; virtual void transferBit(FunkyBoy::u8_fast bit, std::function callback) = 0; }; diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 7c5c35b..628c409 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -156,9 +156,12 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { #if FB_HAS_SOCKETS if (config.socketServer) { - socketInterface = std::make_shared(config); + socketInterface = std::make_shared(); } else if (!config.socketAddress.empty()) { - socketInterface = std::make_shared(config); + socketInterface = std::make_shared(); + } + if (socketInterface) { + socketInterface->init(config); } #endif From c4637461b0e01b8eeb3ba1e367a07a80f38de022 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Wed, 19 May 2021 18:46:07 +0200 Subject: [PATCH 08/15] [WIP] Get two instances to talk with each other (#25) --- core/source/controllers/serial.h | 3 +- core/source/controllers/serial_null.cpp | 6 +- core/source/controllers/serial_null.h | 3 +- core/source/memory/memory.cpp | 8 +- .../source/controllers/serial_sdl.cpp | 14 ++- platform-sdl/source/controllers/serial_sdl.h | 5 +- platform-sdl/source/sockets/bsd_client.cpp | 7 +- platform-sdl/source/sockets/bsd_client.h | 2 +- platform-sdl/source/sockets/bsd_common.cpp | 96 +++++++++++++++++-- platform-sdl/source/sockets/bsd_common.h | 17 +++- platform-sdl/source/sockets/bsd_server.cpp | 6 +- platform-sdl/source/sockets/bsd_server.h | 2 +- .../source/sockets/socket_interface.h | 4 +- 13 files changed, 137 insertions(+), 36 deletions(-) diff --git a/core/source/controllers/serial.h b/core/source/controllers/serial.h index b73a516..53be36f 100644 --- a/core/source/controllers/serial.h +++ b/core/source/controllers/serial.h @@ -28,7 +28,8 @@ namespace FunkyBoy::Controller { virtual ~SerialController() = default; virtual void setup(std::function bitReceived) = 0; - virtual void sendBit(u8 data) = 0; + virtual void transferByte() = 0; + virtual void setByte(u8_fast byte) = 0; }; typedef std::shared_ptr SerialControllerPtr; diff --git a/core/source/controllers/serial_null.cpp b/core/source/controllers/serial_null.cpp index 1f09717..15a0c96 100644 --- a/core/source/controllers/serial_null.cpp +++ b/core/source/controllers/serial_null.cpp @@ -22,6 +22,10 @@ void SerialControllerVoid::setup(std::function bitReceived) { // Do nothing } -void SerialControllerVoid::sendBit(FunkyBoy::u8 data) { +void SerialControllerVoid::setByte(FunkyBoy::u8_fast byte) { // Do nothing +} + +void SerialControllerVoid::transferByte() { + } \ No newline at end of file diff --git a/core/source/controllers/serial_null.h b/core/source/controllers/serial_null.h index dbd2db9..4bf361e 100644 --- a/core/source/controllers/serial_null.h +++ b/core/source/controllers/serial_null.h @@ -24,7 +24,8 @@ namespace FunkyBoy::Controller { class SerialControllerVoid: public SerialController { public: void setup(std::function bitReceived) override; - void sendBit(u8 data) override; + void transferByte() override; + void setByte(u8_fast byte) override; }; } diff --git a/core/source/memory/memory.cpp b/core/source/memory/memory.cpp index 8bff24c..ce19126 100644 --- a/core/source/memory/memory.cpp +++ b/core/source/memory/memory.cpp @@ -482,9 +482,11 @@ void Memory::write8BitsTo(memory_address offset, u8 val) { if (offset < 0xFF80) { // IO registers - if (offset == FB_REG_SC) { - if (val & 0b10000000) { - controllers->getSerial()->sendBit(read8BitsAt(FB_REG_SB)); + if (offset == FB_REG_SB) { + controllers->getSerial()->setByte(read8BitsAt(FB_REG_SB)); + } else if (offset == FB_REG_SC) { + if ((val & 0b10000001) == 0b10000001) { + controllers->getSerial()->transferByte(); } } else if (offset == FB_REG_DMA) { dmaStarted = true; diff --git a/platform-sdl/source/controllers/serial_sdl.cpp b/platform-sdl/source/controllers/serial_sdl.cpp index cf886cd..59020cd 100644 --- a/platform-sdl/source/controllers/serial_sdl.cpp +++ b/platform-sdl/source/controllers/serial_sdl.cpp @@ -26,11 +26,19 @@ SerialControllerSDL::SerialControllerSDL(SDL::Sockets::SocketInterfacePtr socket #endif void SerialControllerSDL::setup(std::function bitReceivedCallback) { - this->bitReceived = bitReceivedCallback; +#if FB_HAS_SOCKETS + socketInterface->setCallback(bitReceivedCallback); +#endif +} + +void SerialControllerSDL::setByte(FunkyBoy::u8_fast data) { +#if FB_HAS_SOCKETS + socketInterface->setInputByte(data); +#endif } -void SerialControllerSDL::sendBit(FunkyBoy::u8 data) { +void SerialControllerSDL::transferByte() { #if FB_HAS_SOCKETS - socketInterface->transferBit(data, bitReceived); + socketInterface->transferByte(); #endif } \ No newline at end of file diff --git a/platform-sdl/source/controllers/serial_sdl.h b/platform-sdl/source/controllers/serial_sdl.h index dfc4806..f9e692a 100644 --- a/platform-sdl/source/controllers/serial_sdl.h +++ b/platform-sdl/source/controllers/serial_sdl.h @@ -27,8 +27,6 @@ namespace FunkyBoy::Controller { class SerialControllerSDL: public SerialController { private: - std::function bitReceived; - #if FB_HAS_SOCKETS SDL::Sockets::SocketInterfacePtr socketInterface; #endif @@ -38,7 +36,8 @@ namespace FunkyBoy::Controller { #endif void setup(std::function bitReceived) override; - void sendBit(u8 data) override; + void transferByte() override; + void setByte(u8_fast byte) override; }; } diff --git a/platform-sdl/source/sockets/bsd_client.cpp b/platform-sdl/source/sockets/bsd_client.cpp index fe0cd15..613b7fd 100644 --- a/platform-sdl/source/sockets/bsd_client.cpp +++ b/platform-sdl/source/sockets/bsd_client.cpp @@ -58,10 +58,7 @@ void BSDClient::setupSocket(const CLIConfig &config) { std::cout << "Connection is trusted" << std::endl; } -void BSDClient::threadMain() { +void BSDClient::readThreadMain() { char buffer[16] = {0}; - size_t bytesRead; - while (socketFd > 0) { - // TODO: Handle serial bits - } + handleSocketRead(socketFd, buffer); } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_client.h b/platform-sdl/source/sockets/bsd_client.h index d88cde0..5741878 100644 --- a/platform-sdl/source/sockets/bsd_client.h +++ b/platform-sdl/source/sockets/bsd_client.h @@ -26,7 +26,7 @@ namespace FunkyBoy::SDL::Sockets { class BSDClient: public BSDSocketInterface { protected: void setupSocket(const CLIConfig &config) override; - void threadMain() override; + void readThreadMain() override; }; } diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp index 4c54e06..d092c89 100644 --- a/platform-sdl/source/sockets/bsd_common.cpp +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -23,11 +23,14 @@ using namespace FunkyBoy::SDL::Sockets; BSDSocketInterface::BSDSocketInterface() : socketFd(0) + , outByte(0) + , transferring(false) + , running(false) { } BSDSocketInterface::~BSDSocketInterface() { - if (thread.joinable()) { + if (socketFd > 0) { #ifdef FB_DEBUG std::cout << "Closing socket file descriptor..." << std::endl; #endif @@ -35,23 +38,100 @@ BSDSocketInterface::~BSDSocketInterface() { close(socketFd); socketFd = 0; #ifdef FB_DEBUG - std::cout << "Socket file descriptor closed, joining server thread..." << std::endl; + std::cout << "Socket file descriptor closed, joining input thread..." << std::endl; #endif - thread.join(); + if (readThread.joinable()) { + readThread.join(); + } #ifdef FB_DEBUG - std::cout << "Server thread has stopped" << std::endl; + std::cout << "Joining output thread..." << std::endl; +#endif + if (sendThread.joinable()) { + sendThread.join(); + } +#ifdef FB_DEBUG + std::cout << "Threads have been stopped" << std::endl; #endif } } void BSDSocketInterface::init(const CLIConfig &config) { setupSocket(config); - thread = std::thread([&] { - threadMain(); + readThread = std::thread([&] { + readThreadMain(); }); } -void BSDSocketInterface::transferBit(FunkyBoy::u8_fast bit, std::function callback) { +void BSDSocketInterface::handleSocketRead(int fd, char *buffer) { + running = true; + + sendThread = std::thread([&]{ + handleSocketWrite(fd); + }); + + size_t bytesRead; + while ((bytesRead = read(fd, buffer, 1)) > 0) { + fprintf(stderr, "LOCK handleSocketRead\n"); + std::lock_guard lock(mutex); + fprintf(stderr, "LOCK handleSocketRead AQUIRED\n"); + + std::cout << "RECEIVED INCOMING BYTE: " << (buffer[0] & 0xffff) << std::endl; + bitReceivedCallback(buffer[0]); + + buffer[0] = outByte & 0xff; + if (send(fd, buffer, sizeof(buffer), 0) < 1) { +#ifdef FB_DEBUG + std::cerr << "Socket was closed while trying to send a response byte, shutting down read thread..." << std::endl; +#endif + break; + } + } + + running = false; +} + +void BSDSocketInterface::handleSocketWrite(int fd) { + u8 buffer[1] = {0}; + while (running) { + // TODO: Can we suspend the thread until an outgoing byte is available? + if (!transferring) { + continue; + } + fprintf(stderr, "LOCK handleSocketWrite\n"); + std::lock_guard lock(mutex); + fprintf(stderr, "LOCK handleSocketWrite AQUIRED\n"); + buffer[0] = outByte & 0xff; + if (send(fd, buffer, sizeof(buffer), 0) < 1) { +#ifdef FB_DEBUG + std::cerr << "Socket was closed while trying to send a byte, shutting down write thread..." << std::endl; +#endif + return; + } + if (read(fd, buffer, sizeof(buffer)) <= 0) { +#ifdef FB_DEBUG + std::cerr << "Socket was closed while trying to receive response byte, shutting down write thread..." << std::endl; +#endif + return; + } + + std::cout << "RECEIVED RESPONSE BYTE: " << (buffer[0] & 0xffff) << std::endl; + bitReceivedCallback(buffer[0]); + + transferring = false; + } +} + +void BSDSocketInterface::setInputByte(FunkyBoy::u8_fast byte) { + outByte = byte; +} + +void BSDSocketInterface::setCallback(std::function callback) { + bitReceivedCallback = callback; +} + +void BSDSocketInterface::transferByte() { + fprintf(stderr, "LOCK transferByte\n"); std::lock_guard lock(mutex); - // TODO: queue.push(bit); + fprintf(stderr, "LOCK transferByte AQUIRED\n"); + transferring = true; } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_common.h b/platform-sdl/source/sockets/bsd_common.h index 253e122..651baae 100644 --- a/platform-sdl/source/sockets/bsd_common.h +++ b/platform-sdl/source/sockets/bsd_common.h @@ -27,14 +27,21 @@ namespace FunkyBoy::SDL::Sockets { class BSDSocketInterface : public SocketInterface { private: - std::thread thread; - + bool running; + std::thread sendThread, readThread; + std::function bitReceivedCallback; protected: std::mutex mutex; int socketFd; struct sockaddr_in address{}; - virtual void threadMain() = 0; + bool transferring; + u8_fast outByte; + + void handleSocketRead(int fd, char *buffer); + void handleSocketWrite(int fd); + + virtual void readThreadMain() = 0; virtual void setupSocket(const CLIConfig &config) = 0; public: @@ -42,7 +49,9 @@ namespace FunkyBoy::SDL::Sockets { ~BSDSocketInterface() override; void init(const CLIConfig &config) final; - void transferBit(FunkyBoy::u8_fast bit, std::function callback) final; + void setInputByte(FunkyBoy::u8_fast byte) final; + void setCallback(std::function bitReceivedCallback) final; + void transferByte() final; }; } diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp index dc969ea..fff3ea5 100644 --- a/platform-sdl/source/sockets/bsd_server.cpp +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -44,7 +44,7 @@ void BSDServer::setupSocket(const CLIConfig &config) { } } -void BSDServer::threadMain() { +void BSDServer::readThreadMain() { int addrlen = sizeof(address); char buffer[16] = {0}; while (socketFd > 0) { @@ -78,8 +78,6 @@ void BSDServer::threadMain() { std::cout << "Connection from " << clientSocket << " is trusted" << std::endl; - while ((bytesRead = read(clientSocket, buffer, sizeof(buffer))) > 0) { - // TODO: Transfer bit to serial controller - } + handleSocketRead(clientSocket, buffer); } } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_server.h b/platform-sdl/source/sockets/bsd_server.h index 6c4da28..5ec926a 100644 --- a/platform-sdl/source/sockets/bsd_server.h +++ b/platform-sdl/source/sockets/bsd_server.h @@ -24,7 +24,7 @@ namespace FunkyBoy::SDL::Sockets { class BSDServer: public BSDSocketInterface { protected: void setupSocket(const CLIConfig &config) override; - void threadMain() override; + void readThreadMain() override; }; } diff --git a/platform-sdl/source/sockets/socket_interface.h b/platform-sdl/source/sockets/socket_interface.h index 15a172d..9c713d7 100644 --- a/platform-sdl/source/sockets/socket_interface.h +++ b/platform-sdl/source/sockets/socket_interface.h @@ -30,7 +30,9 @@ namespace FunkyBoy::SDL::Sockets { virtual ~SocketInterface() = default; virtual void init(const CLIConfig &config) = 0; - virtual void transferBit(FunkyBoy::u8_fast bit, std::function callback) = 0; + virtual void setInputByte(FunkyBoy::u8_fast byte) = 0; + virtual void setCallback(std::function bitReceivedCallback) = 0; + virtual void transferByte() = 0; }; typedef std::shared_ptr SocketInterfacePtr; From d8b4b9b21f9b3cdc4be512cd6aa5e26ede69f7e6 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Fri, 21 May 2021 23:29:52 +0200 Subject: [PATCH 09/15] [WIP] Fix exchange of bytes (#25) --- platform-sdl/source/sockets/bsd_client.cpp | 4 ++-- platform-sdl/source/sockets/bsd_common.cpp | 27 +++++++++++++--------- platform-sdl/source/sockets/bsd_common.h | 2 +- platform-sdl/source/sockets/bsd_server.cpp | 4 ++-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/platform-sdl/source/sockets/bsd_client.cpp b/platform-sdl/source/sockets/bsd_client.cpp index 613b7fd..a6d9a01 100644 --- a/platform-sdl/source/sockets/bsd_client.cpp +++ b/platform-sdl/source/sockets/bsd_client.cpp @@ -59,6 +59,6 @@ void BSDClient::setupSocket(const CLIConfig &config) { } void BSDClient::readThreadMain() { - char buffer[16] = {0}; - handleSocketRead(socketFd, buffer); + u8 buffer[16] = {0}; + handleSocketRead(socketFd, buffer, sizeof(buffer)); } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp index d092c89..92ca285 100644 --- a/platform-sdl/source/sockets/bsd_common.cpp +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -21,6 +21,12 @@ using namespace FunkyBoy::SDL::Sockets; +#ifdef FB_DEBUG +#define lock_println(...) fprintf(stdout, __VA_ARGS__) +#else +#define lock_println(...) ((void)0) +#endif + BSDSocketInterface::BSDSocketInterface() : socketFd(0) , outByte(0) @@ -62,7 +68,7 @@ void BSDSocketInterface::init(const CLIConfig &config) { }); } -void BSDSocketInterface::handleSocketRead(int fd, char *buffer) { +void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) { running = true; sendThread = std::thread([&]{ @@ -70,16 +76,17 @@ void BSDSocketInterface::handleSocketRead(int fd, char *buffer) { }); size_t bytesRead; - while ((bytesRead = read(fd, buffer, 1)) > 0) { - fprintf(stderr, "LOCK handleSocketRead\n"); + while ((bytesRead = read(fd, buffer, bufferSize)) > 0) { + lock_println("[LOCK] handleSocketRead %zu\n", bytesRead); std::lock_guard lock(mutex); - fprintf(stderr, "LOCK handleSocketRead AQUIRED\n"); + lock_println("[LOCK] handleSocketRead AQUIRED\n"); std::cout << "RECEIVED INCOMING BYTE: " << (buffer[0] & 0xffff) << std::endl; bitReceivedCallback(buffer[0]); buffer[0] = outByte & 0xff; - if (send(fd, buffer, sizeof(buffer), 0) < 1) { + fprintf(stdout, "send response byte %d\n", outByte); + if (send(fd, buffer, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a response byte, shutting down read thread..." << std::endl; #endif @@ -97,11 +104,11 @@ void BSDSocketInterface::handleSocketWrite(int fd) { if (!transferring) { continue; } - fprintf(stderr, "LOCK handleSocketWrite\n"); + lock_println("[LOCK] handleSocketWrite\n"); std::lock_guard lock(mutex); - fprintf(stderr, "LOCK handleSocketWrite AQUIRED\n"); + lock_println("[LOCK] handleSocketWrite AQUIRED\n"); buffer[0] = outByte & 0xff; - if (send(fd, buffer, sizeof(buffer), 0) < 1) { + if (send(fd, buffer, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a byte, shutting down write thread..." << std::endl; #endif @@ -130,8 +137,6 @@ void BSDSocketInterface::setCallback(std::function callback) { } void BSDSocketInterface::transferByte() { - fprintf(stderr, "LOCK transferByte\n"); - std::lock_guard lock(mutex); - fprintf(stderr, "LOCK transferByte AQUIRED\n"); + fprintf(stdout, "transferByte(%d)\n", outByte); transferring = true; } \ No newline at end of file diff --git a/platform-sdl/source/sockets/bsd_common.h b/platform-sdl/source/sockets/bsd_common.h index 651baae..be291d4 100644 --- a/platform-sdl/source/sockets/bsd_common.h +++ b/platform-sdl/source/sockets/bsd_common.h @@ -38,7 +38,7 @@ namespace FunkyBoy::SDL::Sockets { bool transferring; u8_fast outByte; - void handleSocketRead(int fd, char *buffer); + void handleSocketRead(int fd, u8 *buffer, size_t bufferSize); void handleSocketWrite(int fd); virtual void readThreadMain() = 0; diff --git a/platform-sdl/source/sockets/bsd_server.cpp b/platform-sdl/source/sockets/bsd_server.cpp index fff3ea5..d815566 100644 --- a/platform-sdl/source/sockets/bsd_server.cpp +++ b/platform-sdl/source/sockets/bsd_server.cpp @@ -46,7 +46,7 @@ void BSDServer::setupSocket(const CLIConfig &config) { void BSDServer::readThreadMain() { int addrlen = sizeof(address); - char buffer[16] = {0}; + u8 buffer[16] = {0}; while (socketFd > 0) { #ifdef FB_DEBUG std::cout << "Accepting on socket..." << std::endl; @@ -78,6 +78,6 @@ void BSDServer::readThreadMain() { std::cout << "Connection from " << clientSocket << " is trusted" << std::endl; - handleSocketRead(clientSocket, buffer); + handleSocketRead(clientSocket, buffer, sizeof(buffer)); } } \ No newline at end of file From 366bacd0706782ef4d71d7d5f042e44e5a6af0f9 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 22 May 2021 00:54:10 +0200 Subject: [PATCH 10/15] [WIP] Step to get serial to work (#25) --- core/source/emulator/cpu.cpp | 2 +- core/source/memory/memory.cpp | 49 +++++++++++++++------- core/source/memory/memory.h | 7 +++- platform-sdl/source/sockets/bsd_common.cpp | 3 ++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/core/source/emulator/cpu.cpp b/core/source/emulator/cpu.cpp index 99b4091..2bd0c1c 100644 --- a/core/source/emulator/cpu.cpp +++ b/core/source/emulator/cpu.cpp @@ -160,7 +160,7 @@ ret_code CPU::doCycle(Memory &memory) { ret_code result = FB_RET_SUCCESS; if (instrContext.cpuState == CPUState::RUNNING) { - memory.doDMA(); // TODO: Implement delay of 2 clocks + memory.onTick(); // TODO: Implement delay of 2 clocks auto op = *operands; diff --git a/core/source/memory/memory.cpp b/core/source/memory/memory.cpp index ce19126..5154953 100644 --- a/core/source/memory/memory.cpp +++ b/core/source/memory/memory.cpp @@ -54,6 +54,8 @@ Memory::Memory(Controller::ControllersPtr controllers, const io_registers& ioReg #ifdef FB_USE_AUTOSAVE , cartridgeRAMWritten(false) #endif + , serialTransferClocks(-2) + , receivedByte(-1) { internalRam = new u8[FB_INTERNAL_RAM_SIZE]{}; hram = new u8[FB_HRAM_SIZE]{}; @@ -93,14 +95,8 @@ namespace FunkyBoy::Util { void Memory::loadROM(std::istream &stream, bool strictSizeCheck) { controllers->getSerial()->setup([&](u8_fast data) { std::cout << "Received data: " << (data & 0xFFFF) << std::endl; - - u8 &sb = ioRegisters.getSB(); - sb = (sb << 1) | (data & 0b1); - - u8 &sc = ioRegisters.getSC(); - sc &= 0b01111111; - - ioRegisters.requestInterrupt(InterruptType::SERIAL); + receivedByte = data; + serialTransferClocks = 7; }); if (!stream.good()) { @@ -483,7 +479,7 @@ void Memory::write8BitsTo(memory_address offset, u8 val) { // IO registers if (offset == FB_REG_SB) { - controllers->getSerial()->setByte(read8BitsAt(FB_REG_SB)); + controllers->getSerial()->setByte(val); } else if (offset == FB_REG_SC) { if ((val & 0b10000001) == 0b10000001) { controllers->getSerial()->transferByte(); @@ -510,14 +506,37 @@ void Memory::write8BitsTo(memory_address offset, u8 val) { } } -void Memory::doDMA() { - if (!dmaStarted) { - return; +void Memory::onTick() { + if (dmaStarted) { + ppuMemory.getOAMByte(dmaLsb) = read8BitsAt(Util::compose16Bits(dmaLsb, dmaMsb)); + if (++dmaLsb > 0x9F) { + dmaStarted = false; + } + } + if (serialTransferClocks > -2) { + if (serialTransferClocks == -1 || (serialTransferClocks > -1 && --serialTransferClocks == -1)) { + handleReceivedByte(); + } } - ppuMemory.getOAMByte(dmaLsb) = read8BitsAt(Util::compose16Bits(dmaLsb, dmaMsb)); - if (++dmaLsb > 0x9F) { - dmaStarted = false; +} + +void Memory::handleReceivedByte() { + if (receivedByte < 0) { + return; } + + /*u8 &sb = ioRegisters.getSB(); + sb = (sb << 1) | (receivedByte & 0b1);*/ + ioRegisters.getSB() = receivedByte; + + u8 &sc = ioRegisters.getSC(); + sc &= 0b01111111; + + receivedByte = -1; + serialTransferClocks = -2; + + fprintf(stdout, "[INTR] Serial\n"); + ioRegisters.requestInterrupt(InterruptType::SERIAL); } void Memory::serialize(std::ostream &ostream) const { diff --git a/core/source/memory/memory.h b/core/source/memory/memory.h index 5a4e6a7..0a017ab 100644 --- a/core/source/memory/memory.h +++ b/core/source/memory/memory.h @@ -48,6 +48,11 @@ namespace FunkyBoy { // Do not free these pointers, they are proxies to the ones above: u8 *dynamicRamBank; + int serialTransferClocks; + int_fast16_t receivedByte; + + void handleReceivedByte(); + test_public: u8 *rom; u8 *cram; @@ -84,7 +89,7 @@ namespace FunkyBoy { void write8BitsTo(memory_address offset, u8 val); - void doDMA(); + void onTick(); inline u8 getIE() { return interruptEnableRegister; diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp index 92ca285..9df4fdc 100644 --- a/platform-sdl/source/sockets/bsd_common.cpp +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -92,6 +92,7 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) #endif break; } + lock_println("[LOCK] handleSocketRead RELEASED\n"); } running = false; @@ -114,6 +115,7 @@ void BSDSocketInterface::handleSocketWrite(int fd) { #endif return; } + fprintf(stdout, "wrote %d, reading...\n", outByte); if (read(fd, buffer, sizeof(buffer)) <= 0) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to receive response byte, shutting down write thread..." << std::endl; @@ -125,6 +127,7 @@ void BSDSocketInterface::handleSocketWrite(int fd) { bitReceivedCallback(buffer[0]); transferring = false; + lock_println("[LOCK] handleSocketWrite RELEASED\n"); } } From b798f1b88f5304a1bb1e2cf2009d3bf1eb7ef4eb Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sun, 6 Jun 2021 16:11:33 +0200 Subject: [PATCH 11/15] Minor fixes after rebase (#25) --- platform-sdl/source/sockets/bsd_client.cpp | 4 ++-- platform-sdl/source/window/window.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platform-sdl/source/sockets/bsd_client.cpp b/platform-sdl/source/sockets/bsd_client.cpp index a6d9a01..07b8f3f 100644 --- a/platform-sdl/source/sockets/bsd_client.cpp +++ b/platform-sdl/source/sockets/bsd_client.cpp @@ -32,8 +32,8 @@ void BSDClient::setupSocket(const CLIConfig &config) { address.sin_family = AF_INET; address.sin_port = htons(config.socketPort); // TODO: Support domains - if (inet_pton(AF_INET, config.socketAddress, &address.sin_addr) <= 0) { - throw SocketException("Invalid address or address not supported: " + std::string(config.socketAddress)); + if (inet_pton(AF_INET, config.socketAddress.c_str(), &address.sin_addr) <= 0) { + throw SocketException("Invalid address or address not supported: " + config.socketAddress); } if (connect(socketFd, reinterpret_cast(&address), sizeof(address)) < 0) { throw SocketException("Connection failed"); diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 628c409..3cc24a5 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -75,9 +75,9 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { options.add_options() #if FB_HAS_SOCKETS ("server", "Start a server for multiplayer", - cxxopts::value()->default_value("8020")) - ("client", "Connect to a server for multiplayer (address:port)", - cxxopts::value()->default_value("localhost:8020"), "Expected format: :") + cxxopts::value()->default_value("8020"), "") + ("client", "Connect to a server for multiplayer", + cxxopts::value()->default_value("localhost:8020"), ":") #endif ("t,test", "Test whether the application can start correctly") ("h,help", "Print usage") @@ -102,7 +102,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { config.socketServer = true; config.socketPort = result["server"].as(); } else if (result.count("client")) { - std::regex socketAddressRegex("([a-ZA-Z0-9\\.-_]+):([0-9]+)"); + std::regex socketAddressRegex("([a-zA-Z0-9\\.\\-_]+):([0-9]+)"); std::smatch matches; if (!std::regex_search(result["client"].as(), matches, socketAddressRegex)) { std::cerr << "Client address needs to be in : format!" << std::endl; From 4587ce0045c7d2caf908258ce49c3f28fd2737b3 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Fri, 2 Jul 2021 23:50:41 +0200 Subject: [PATCH 12/15] Get serial connection to work more or less (#25) --- platform-sdl/source/sockets/bsd_common.cpp | 37 ++++++++++++++++------ platform-sdl/source/sockets/bsd_common.h | 10 +++++- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp index 9df4fdc..4dc48c2 100644 --- a/platform-sdl/source/sockets/bsd_common.cpp +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -19,16 +19,17 @@ #include #include -using namespace FunkyBoy::SDL::Sockets; - #ifdef FB_DEBUG #define lock_println(...) fprintf(stdout, __VA_ARGS__) #else #define lock_println(...) ((void)0) #endif +using namespace FunkyBoy::SDL::Sockets; + BSDSocketInterface::BSDSocketInterface() : socketFd(0) + , mode(BSDSocketMode::IDLE) , outByte(0) , transferring(false) , running(false) @@ -77,8 +78,16 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) size_t bytesRead; while ((bytesRead = read(fd, buffer, bufferSize)) > 0) { + if (mode == BSDSocketMode::AWAITING_RESPONSE) { + responsePromise.set_value(buffer[0]); + continue; + } + if (mode != BSDSocketMode::IDLE) { + lock_println("[NON IDLE] RECEIVED byte %d\n", (buffer[0] & 0xffff)); + continue; + } lock_println("[LOCK] handleSocketRead %zu\n", bytesRead); - std::lock_guard lock(mutex); + mode = BSDSocketMode::RESPONDING; lock_println("[LOCK] handleSocketRead AQUIRED\n"); std::cout << "RECEIVED INCOMING BYTE: " << (buffer[0] & 0xffff) << std::endl; @@ -86,12 +95,15 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) buffer[0] = outByte & 0xff; fprintf(stdout, "send response byte %d\n", outByte); + //mode = BSDSocketMode::SENDING; if (send(fd, buffer, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a response byte, shutting down read thread..." << std::endl; #endif + mode = BSDSocketMode::IDLE; break; } + mode = BSDSocketMode::IDLE; lock_println("[LOCK] handleSocketRead RELEASED\n"); } @@ -100,33 +112,40 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) void BSDSocketInterface::handleSocketWrite(int fd) { u8 buffer[1] = {0}; + u8 response; while (running) { // TODO: Can we suspend the thread until an outgoing byte is available? - if (!transferring) { + if (!transferring || mode != BSDSocketMode::IDLE) { continue; } lock_println("[LOCK] handleSocketWrite\n"); - std::lock_guard lock(mutex); + mode = BSDSocketMode::AWAITING_RESPONSE; lock_println("[LOCK] handleSocketWrite AQUIRED\n"); buffer[0] = outByte & 0xff; if (send(fd, buffer, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a byte, shutting down write thread..." << std::endl; #endif + mode = BSDSocketMode::IDLE; return; } + //mode = BSDSocketMode::RECEIVING_RESPONSE; fprintf(stdout, "wrote %d, reading...\n", outByte); - if (read(fd, buffer, sizeof(buffer)) <= 0) { + /* if (read(fd, buffer, sizeof(buffer)) <= 0) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to receive response byte, shutting down write thread..." << std::endl; #endif + mode = BSDSocketMode::IDLE; return; - } + } */ + response = responsePromise.get_future().get(); + responsePromise = std::promise(); - std::cout << "RECEIVED RESPONSE BYTE: " << (buffer[0] & 0xffff) << std::endl; - bitReceivedCallback(buffer[0]); + std::cout << "RECEIVED RESPONSE BYTE: " << response << std::endl; + bitReceivedCallback(response); transferring = false; + mode = BSDSocketMode::IDLE; lock_println("[LOCK] handleSocketWrite RELEASED\n"); } } diff --git a/platform-sdl/source/sockets/bsd_common.h b/platform-sdl/source/sockets/bsd_common.h index be291d4..74b6efd 100644 --- a/platform-sdl/source/sockets/bsd_common.h +++ b/platform-sdl/source/sockets/bsd_common.h @@ -22,16 +22,24 @@ #include #include #include +#include namespace FunkyBoy::SDL::Sockets { + enum BSDSocketMode { + IDLE, + RESPONDING, + AWAITING_RESPONSE, + }; + class BSDSocketInterface : public SocketInterface { private: bool running; std::thread sendThread, readThread; std::function bitReceivedCallback; + std::promise responsePromise; protected: - std::mutex mutex; + BSDSocketMode mode; int socketFd; struct sockaddr_in address{}; From 7bfaad9290ffef503c552038adb04e1161d565d6 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sat, 3 Jul 2021 23:17:32 +0200 Subject: [PATCH 13/15] Cleanup code (#25) --- platform-sdl/source/sockets/bsd_common.cpp | 35 ++++++++-------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/platform-sdl/source/sockets/bsd_common.cpp b/platform-sdl/source/sockets/bsd_common.cpp index 4dc48c2..4fc3534 100644 --- a/platform-sdl/source/sockets/bsd_common.cpp +++ b/platform-sdl/source/sockets/bsd_common.cpp @@ -21,8 +21,10 @@ #ifdef FB_DEBUG #define lock_println(...) fprintf(stdout, __VA_ARGS__) +#define serial_println(...) fprintf(stdout, __VA_ARGS__) #else #define lock_println(...) ((void)0) +#define serial_println(...) ((void)0) #endif using namespace FunkyBoy::SDL::Sockets; @@ -88,14 +90,13 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) } lock_println("[LOCK] handleSocketRead %zu\n", bytesRead); mode = BSDSocketMode::RESPONDING; - lock_println("[LOCK] handleSocketRead AQUIRED\n"); + lock_println("[LOCK] handleSocketRead ACQUIRED\n"); std::cout << "RECEIVED INCOMING BYTE: " << (buffer[0] & 0xffff) << std::endl; bitReceivedCallback(buffer[0]); buffer[0] = outByte & 0xff; - fprintf(stdout, "send response byte %d\n", outByte); - //mode = BSDSocketMode::SENDING; + serial_println("send response byte %d\n", outByte); if (send(fd, buffer, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a response byte, shutting down read thread..." << std::endl; @@ -111,38 +112,28 @@ void BSDSocketInterface::handleSocketRead(int fd, u8 *buffer, size_t bufferSize) } void BSDSocketInterface::handleSocketWrite(int fd) { - u8 buffer[1] = {0}; - u8 response; + u8 byte; while (running) { - // TODO: Can we suspend the thread until an outgoing byte is available? if (!transferring || mode != BSDSocketMode::IDLE) { continue; } lock_println("[LOCK] handleSocketWrite\n"); mode = BSDSocketMode::AWAITING_RESPONSE; - lock_println("[LOCK] handleSocketWrite AQUIRED\n"); - buffer[0] = outByte & 0xff; - if (send(fd, buffer, 1, 0) < 1) { + lock_println("[LOCK] handleSocketWrite ACQUIRED\n"); + byte = outByte & 0xff; + if (send(fd, &byte, 1, 0) < 1) { #ifdef FB_DEBUG std::cerr << "Socket was closed while trying to send a byte, shutting down write thread..." << std::endl; #endif mode = BSDSocketMode::IDLE; return; } - //mode = BSDSocketMode::RECEIVING_RESPONSE; - fprintf(stdout, "wrote %d, reading...\n", outByte); - /* if (read(fd, buffer, sizeof(buffer)) <= 0) { -#ifdef FB_DEBUG - std::cerr << "Socket was closed while trying to receive response byte, shutting down write thread..." << std::endl; -#endif - mode = BSDSocketMode::IDLE; - return; - } */ - response = responsePromise.get_future().get(); + serial_println("wrote %d, reading...\n", outByte); + byte = responsePromise.get_future().get(); responsePromise = std::promise(); - std::cout << "RECEIVED RESPONSE BYTE: " << response << std::endl; - bitReceivedCallback(response); + serial_println("RECEIVED RESPONSE BYTE: %d\n", byte & 0xffff); + bitReceivedCallback(byte); transferring = false; mode = BSDSocketMode::IDLE; @@ -159,6 +150,6 @@ void BSDSocketInterface::setCallback(std::function callback) { } void BSDSocketInterface::transferByte() { - fprintf(stdout, "transferByte(%d)\n", outByte); + serial_println("transferByte(%d)\n", outByte); transferring = true; } \ No newline at end of file From 74c8e8ebcd84f76f4b4eba1ec8fcca319bca9b02 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sun, 4 Jul 2021 12:11:27 +0200 Subject: [PATCH 14/15] Fix test compilation (#25) --- test/source/controllers/serial_test.cpp | 14 +++++++++++--- test/source/controllers/serial_test.h | 6 +++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/test/source/controllers/serial_test.cpp b/test/source/controllers/serial_test.cpp index f9ffd4f..471bb2e 100644 --- a/test/source/controllers/serial_test.cpp +++ b/test/source/controllers/serial_test.cpp @@ -19,10 +19,18 @@ using namespace FunkyBoy::Controller; -void SerialControllerTest::sendByte(FunkyBoy::u8 data) { - std::cout << data; +void SerialControllerTest::setup(std::function) { + // No-op +} + +void SerialControllerTest::setByte(u8_fast byte) { + outByte = byte; +} + +void SerialControllerTest::transferByte() { + std::cout << outByte; for (u8 i = 1 ; i < FB_TEST_SERIAL_CONTROLLER_LWORD_SIZE ; i++) { lastWord[i - 1] = lastWord[i]; } - lastWord[FB_TEST_SERIAL_CONTROLLER_LWORD_SIZE - 1] = data; + lastWord[FB_TEST_SERIAL_CONTROLLER_LWORD_SIZE - 1] = outByte; } diff --git a/test/source/controllers/serial_test.h b/test/source/controllers/serial_test.h index 33d5a60..104a844 100644 --- a/test/source/controllers/serial_test.h +++ b/test/source/controllers/serial_test.h @@ -25,8 +25,12 @@ namespace FunkyBoy::Controller { class SerialControllerTest: public SerialController { + private: + u8 outByte{}; public: - void sendByte(u8 data) override; + void setup(std::function bitReceived) override; + void transferByte() override; + void setByte(u8_fast byte) override; char lastWord[FB_TEST_SERIAL_CONTROLLER_LWORD_SIZE + 1]{}; }; From ef3ee604c4b42cb99907ce48bfc9e31613b556c0 Mon Sep 17 00:00:00 2001 From: Michel Kremer Date: Sun, 4 Jul 2021 17:40:28 +0200 Subject: [PATCH 15/15] Fix compiling error --- platform-sdl/source/window/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-sdl/source/window/window.cpp b/platform-sdl/source/window/window.cpp index 8d31d66..f7bc0d5 100644 --- a/platform-sdl/source/window/window.cpp +++ b/platform-sdl/source/window/window.cpp @@ -192,7 +192,7 @@ bool Window::init(int argc, char **argv, size_t width, size_t height) { return true; } else { std::string errorMessage = "ROM could not be loaded from "; - errorMessage += romPath.generic_string(); + errorMessage += config.romPath.generic_string(); errorMessage += "\nReason: "; errorMessage += getCartridgeStatusDescription(status); errorMessage += " (Status: ";