Python: Add callbacks
Vicki Pfau vi@endrift.com
Fri, 07 Jul 2017 21:51:11 -0700
11 files changed,
120 insertions(+),
30 deletions(-)
jump to
M
src/platform/python/CMakeLists.txt
→
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)
M
src/platform/python/_builder.h
→
src/platform/python/_builder.h
@@ -35,6 +35,7 @@ #include <mgba/core/thread.h>
#include <mgba/core/version.h> #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"
M
src/platform/python/_builder.py
→
src/platform/python/_builder.py
@@ -38,6 +38,7 @@ #include <mgba-util/png-io.h>
#include <mgba-util/vfs.h> #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 @@ """, include_dirs=[incdir, srcdir],
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)
A
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 <mgba/core/core.h> + +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; +}
A
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 <mgba-util/common.h> + +#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);
M
src/platform/python/log.c
→
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 <mgba/core/log.h> - -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;
M
src/platform/python/log.h
→
src/platform/python/log.h
@@ -5,6 +5,8 @@ * 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 <mgba/core/log.h> +#include "pycommon.h" + struct mLoggerPy { struct mLogger d; void* pyobj;
M
src/platform/python/mgba/core.py
→
src/platform/python/mgba/core.py
@@ -4,7 +4,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/. 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 @@ raise RuntimeError("Core is protected")
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,25 +197,33 @@
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):
A
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 <mgba-util/common.h> + +#ifndef PYEXPORT +#define PYEXPORT extern +#endif + +#endif
M
src/platform/python/vfs-py.c
→
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 <mgba-util/vfs.h> - -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) {
M
src/platform/python/vfs-py.h
→
src/platform/python/vfs-py.h
@@ -3,8 +3,9 @@ *
* 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 <mgba-util/vfs.h> -#include <mgba-util/vfs.h> +#include "pycommon.h" struct VFilePy { struct VFile d;