Python: Add callbacks

This commit is contained in:
Vicki Pfau 2017-07-07 21:51:11 -07:00
parent 25b4faef12
commit d1ef27cff9
11 changed files with 120 additions and 30 deletions

View File

@ -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)

View File

@ -35,6 +35,7 @@ void free(void*);
#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"

View File

@ -38,6 +38,7 @@ ffi.set_source("mgba._pylib", """
#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 @@ 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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -5,6 +5,8 @@
* 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;

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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 <mgba-util/vfs.h>
#include "pycommon.h"
struct VFilePy {
struct VFile d;
void* fileobj;