From d1ef27cff90eda02bde9f90cc526e901a4c81d83 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 7 Jul 2017 21:51:11 -0700 Subject: [PATCH] Python: Add callbacks --- src/platform/python/CMakeLists.txt | 5 ++- src/platform/python/_builder.h | 1 + src/platform/python/_builder.py | 3 +- src/platform/python/core.c | 19 ++++++++++ src/platform/python/core.h | 15 ++++++++ src/platform/python/log.c | 9 +---- src/platform/python/log.h | 2 + src/platform/python/mgba/core.py | 61 ++++++++++++++++++++++++++++-- src/platform/python/pycommon.h | 15 ++++++++ src/platform/python/vfs-py.c | 17 +-------- src/platform/python/vfs-py.h | 3 +- 11 files changed, 120 insertions(+), 30 deletions(-) create mode 100644 src/platform/python/core.c create mode 100644 src/platform/python/core.h create mode 100644 src/platform/python/pycommon.h diff --git a/src/platform/python/CMakeLists.txt b/src/platform/python/CMakeLists.txt index 61bc7453b..67f7e57c3 100644 --- a/src/platform/python/CMakeLists.txt +++ b/src/platform/python/CMakeLists.txt @@ -10,17 +10,20 @@ include(FindPythonLibs) list(APPEND DEPENDENCY_LIB ${PYTHON_LIBRARIES}) include_directories(AFTER ${PYTHON_INCLUDE_DIRS}) +file(GLOB PYTHON_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py) add_custom_command(OUTPUT build/lib/${BINARY_NAME}/__init__.py COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. CPPFLAGS="${INCLUDE_FLAGS}" ${PYTHON} ${CMAKE_CURRENT_BINARY_DIR}/setup.py build --build-base ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${BINARY_NAME} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setup.py + DEPENDS ${PYTHON_HEADERS} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py) add_custom_command(OUTPUT lib.c COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. CPPFLAGS="${INCLUDE_FLAGS}" ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib.h + DEPENDS ${PYTHON_HEADERS} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lib.c PROPERTIES GENERATED ON) diff --git a/src/platform/python/_builder.h b/src/platform/python/_builder.h index 1de1ce32f..0af3b4124 100644 --- a/src/platform/python/_builder.h +++ b/src/platform/python/_builder.h @@ -35,6 +35,7 @@ void free(void*); #include #define PYEXPORT extern "Python+C" +#include "platform/python/core.h" #include "platform/python/log.h" #include "platform/python/sio.h" #include "platform/python/vfs-py.h" diff --git a/src/platform/python/_builder.py b/src/platform/python/_builder.py index 91c7ea309..563ebd41b 100644 --- a/src/platform/python/_builder.py +++ b/src/platform/python/_builder.py @@ -38,6 +38,7 @@ ffi.set_source("mgba._pylib", """ #include #define PYEXPORT +#include "platform/python/core.h" #include "platform/python/log.h" #include "platform/python/sio.h" #include "platform/python/vfs-py.h" @@ -46,7 +47,7 @@ ffi.set_source("mgba._pylib", """ extra_compile_args=cppflags, libraries=["mgba"], library_dirs=[bindir], - sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "log.c", "sio.c"]]) + sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "core.c", "log.c", "sio.c"]]) preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True) diff --git a/src/platform/python/core.c b/src/platform/python/core.c new file mode 100644 index 000000000..dccd393d7 --- /dev/null +++ b/src/platform/python/core.c @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include + +struct mCoreCallbacks* mCorePythonCallbackCreate(void* pyobj) { + struct mCoreCallbacks* callbacks = malloc(sizeof(*callbacks)); + callbacks->videoFrameStarted = _mCorePythonCallbacksVideoFrameStarted; + callbacks->videoFrameEnded = _mCorePythonCallbacksVideoFrameEnded; + callbacks->coreCrashed = _mCorePythonCallbacksCoreCrashed; + callbacks->sleep = _mCorePythonCallbacksSleep; + + callbacks->context = pyobj; + return callbacks; +} diff --git a/src/platform/python/core.h b/src/platform/python/core.h new file mode 100644 index 000000000..ed4790917 --- /dev/null +++ b/src/platform/python/core.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + +#include "pycommon.h" + +struct mCoreCallbacks* mCorePythonCallbackCreate(void* pyobj); + +PYEXPORT void _mCorePythonCallbacksVideoFrameStarted(void* user); +PYEXPORT void _mCorePythonCallbacksVideoFrameEnded(void* user); +PYEXPORT void _mCorePythonCallbacksCoreCrashed(void* user); +PYEXPORT void _mCorePythonCallbacksSleep(void* user); diff --git a/src/platform/python/log.c b/src/platform/python/log.c index 53c8201e2..ed3d3f35b 100644 --- a/src/platform/python/log.c +++ b/src/platform/python/log.c @@ -3,14 +3,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -struct mLoggerPy { - struct mLogger d; - void* pyobj; -}; - -void _pyLog(void* logger, int category, enum mLogLevel level, const char* message); +#include "log.h" static void _pyLogShim(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { struct mLoggerPy* pylogger = (struct mLoggerPy*) logger; diff --git a/src/platform/python/log.h b/src/platform/python/log.h index 26ec70253..22df10090 100644 --- a/src/platform/python/log.h +++ b/src/platform/python/log.h @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include "pycommon.h" + struct mLoggerPy { struct mLogger d; void* pyobj; diff --git a/src/platform/python/mgba/core.py b/src/platform/python/mgba/core.py index 50a6e9503..be7d912a6 100644 --- a/src/platform/python/mgba/core.py +++ b/src/platform/python/mgba/core.py @@ -4,7 +4,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from ._pylib import ffi, lib -from . import tile +from . import tile, createCallback from cached_property import cached_property def find(path): @@ -45,11 +45,58 @@ def protected(f): return f(self, *args, **kwargs) return wrapper +@ffi.def_extern() +def _mCorePythonCallbacksVideoFrameStarted(user): + context = ffi.from_handle(user) + context._videoFrameStarted() + +@ffi.def_extern() +def _mCorePythonCallbacksVideoFrameEnded(user): + context = ffi.from_handle(user) + context._videoFrameEnded() + +@ffi.def_extern() +def _mCorePythonCallbacksCoreCrashed(user): + context = ffi.from_handle(user) + context._coreCrashed() + +@ffi.def_extern() +def _mCorePythonCallbacksSleep(user): + context = ffi.from_handle(user) + context._sleep() + +class CoreCallbacks(object): + def __init__(self): + self._handle = ffi.new_handle(self) + self.videoFrameStarted = [] + self.videoFrameEnded = [] + self.coreCrashed = [] + self.sleep = [] + self.context = lib.mCorePythonCallbackCreate(self._handle) + + def _videoFrameStarted(self): + for cb in self.videoFrameStarted: + cb() + + def _videoFrameEnded(self): + for cb in self.videoFrameEnded: + cb() + + def _coreCrashed(self): + for cb in self.coreCrashed: + cb() + + def _sleep(self): + for cb in self.sleep: + cb() + class Core(object): def __init__(self, native): self._core = native self._wasReset = False self._protected = False + self._callbacks = CoreCallbacks() + self._core.addCoreCallbacks(self._core, self._callbacks.context) @cached_property def tiles(self): @@ -150,26 +197,34 @@ class Core(object): def clearKeys(self, *args, **kwargs): self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs)) + @property @needsReset def frameCounter(self): return self._core.frameCounter(self._core) + @property def frameCycles(self): return self._core.frameCycles(self._core) + @property def frequency(self): return self._core.frequency(self._core) - def getGameTitle(self): + @property + def gameTitle(self): title = ffi.new("char[16]") self._core.getGameTitle(self._core, title) return ffi.string(title, 16).decode("ascii") - def getGameCode(self): + @property + def gameCode(self): code = ffi.new("char[12]") self._core.getGameCode(self._core, code) return ffi.string(code, 12).decode("ascii") + def addFrameCallback(self, cb): + self._callbacks.videoFrameEnded.append(cb) + class ICoreOwner(object): def claim(self): raise NotImplementedError diff --git a/src/platform/python/pycommon.h b/src/platform/python/pycommon.h new file mode 100644 index 000000000..29577e346 --- /dev/null +++ b/src/platform/python/pycommon.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PYTHON_COMMON_H +#define PYTHON_COMMON_H + +#include + +#ifndef PYEXPORT +#define PYEXPORT extern +#endif + +#endif diff --git a/src/platform/python/vfs-py.c b/src/platform/python/vfs-py.c index f393832cd..1a90420b1 100644 --- a/src/platform/python/vfs-py.c +++ b/src/platform/python/vfs-py.c @@ -3,22 +3,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include - -struct VFilePy { - struct VFile d; - void* fileobj; -}; - -bool _vfpClose(struct VFile* vf); -off_t _vfpSeek(struct VFile* vf, off_t offset, int whence); -ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size); -ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size); -void* _vfpMap(struct VFile* vf, size_t size, int flags); -void _vfpUnmap(struct VFile* vf, void* memory, size_t size); -void _vfpTruncate(struct VFile* vf, size_t size); -ssize_t _vfpSize(struct VFile* vf); -bool _vfpSync(struct VFile* vf, const void* buffer, size_t size); +#include "vfs-py.h" struct VFile* VFileFromPython(void* fileobj) { if (!fileobj) { diff --git a/src/platform/python/vfs-py.h b/src/platform/python/vfs-py.h index 6cc56dc4c..2f913a741 100644 --- a/src/platform/python/vfs-py.h +++ b/src/platform/python/vfs-py.h @@ -3,9 +3,10 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - #include +#include "pycommon.h" + struct VFilePy { struct VFile d; void* fileobj;