SWIG: test callback & output grabbing

This commit is contained in:
Philippe Teuwen 2020-12-13 23:43:03 +01:00
parent c7e5648164
commit 39710c5fdf
26 changed files with 8332 additions and 6950 deletions

View file

@ -289,11 +289,11 @@ endif
# SWIG #
########
ifneq ("$(wildcard src/pm3_luawrap.c)","")
ifneq ("$(wildcard src/pm3_luawrap.cpp)","")
SWIG_LUA_FOUND = 1
endif
ifeq ($(PYTHON_FOUND),1)
ifneq ("$(wildcard src/pm3_pywrap.c)","")
ifneq ("$(wildcard src/pm3_pywrap.cpp)","")
SWIG_PYTHON_FOUND = 1
endif
endif
@ -305,6 +305,10 @@ PM3CFLAGS = $(CFLAGS)
PM3CFLAGS += -I./src -I./include -I../include -I../common -I../common_fpga $(INCLUDES)
# WIP Testing
#PM3CFLAGS += -std=c11 -pedantic
CXXFLAGS ?= -Wall -Werror -O3
PM3CXXFLAGS = $(CXXFLAGS)
PM3CXXFLAGS += -I../include -I./include -I../common $(INCLUDES)
PREFIX ?= /usr/local
ifneq (,$(findstring MINGW,$(platform)))
@ -330,15 +334,13 @@ endif
ifeq ($(SWIG_LUA_FOUND),1)
PM3CFLAGS += -DHAVE_LUA_SWIG
PM3CXXFLAGS += -DHAVE_LUA_SWIG
endif
ifeq ($(SWIG_PYTHON_FOUND),1)
PM3CFLAGS += -DHAVE_PYTHON_SWIG
PM3CXXFLAGS += -DHAVE_PYTHON_SWIG
endif
CXXFLAGS ?= -Wall -Werror -O3
PM3CXXFLAGS = $(CXXFLAGS)
PM3CXXFLAGS += -I../include -I./include
ifeq ($(QT_FOUND),1)
PM3CFLAGS += -DHAVE_GUI
PM3CXXFLAGS += -DQT_NO_DEBUG
@ -568,7 +570,6 @@ SRCS = aiddesfire.c \
mifare/mifaredefault.c \
mifare/mifarehost.c \
mifare/ndef.c \
pm3.c \
pm3_binlib.c \
pm3_bitlib.c \
preferences.c \
@ -605,10 +606,10 @@ SRCS += bucketsort.c \
SWIGSRCS =
ifeq ($(SWIG_LUA_FOUND),1)
SWIGSRCS += pm3_luawrap.c
SWIGSRCS += pm3_luawrap.cpp
endif
ifeq ($(SWIG_PYTHON_FOUND),1)
SWIGSRCS += pm3_pywrap.c
SWIGSRCS += pm3_pywrap.cpp
endif
# gui
@ -617,6 +618,7 @@ ifeq ($(QT_FOUND),1)
else
CXXSRCS = guidummy.cpp
endif
CXXSRCS += pm3.cpp
# OS X
ifeq ($(platform),Darwin)
@ -624,7 +626,7 @@ ifeq ($(platform),Darwin)
endif
OBJS = $(SRCS:%.c=$(OBJDIR)/%.o)
OBJS += $(SWIGSRCS:%.c=$(OBJDIR)/%.o)
OBJS += $(SWIGSRCS:%.cpp=$(OBJDIR)/%.o)
OBJS += $(CXXSRCS:%.cpp=$(OBJDIR)/%.o)
OBJS += $(OBJCSRCS:%.m=$(OBJDIR)/%.o)
@ -756,13 +758,13 @@ endif
# SWIG #
########
src/pm3_luawrap.c: pm3.i
src/pm3_luawrap.cpp: pm3.i
$(info [=] GEN $@)
$(Q)$(SWIG) -lua -o $@ $<
$(Q)$(SWIG) -c++ -lua -o $@ $<
src/pm3_pywrap.c: pm3.i
src/pm3_pywrap.cpp: pm3.i
$(info [=] GEN $@)
$(Q)$(SWIG) -python -o $@ $<
$(Q)$(SWIG) -c++ -python -o $@ $<
########
# misc #
@ -779,11 +781,12 @@ src/version.c: default_version.c
print-%: ; @echo $* = $($*)
# SWIG files emit a number of warnings, we've to ignore them
%wrap.o: %wrap.c
$(OBJDIR)/%wrap.o : %wrap.c $(OBJDIR)/%.d
$(info [-] CC $<)
%wrap.o: %wrap.cpp
$(OBJDIR)/%wrap.o : %wrap.cpp $(OBJDIR)/%.d
$(info [-] CXX $<)
$(Q)$(MKDIR) $(dir $@)
$(Q)$(CC) $(DEPFLAGS) $(PM3CFLAGS) -Wno-missing-prototypes -Wno-missing-declarations -Wno-missing-field-initializers -c -o $@ $<
# $(Q)$(CXX) $(DEPFLAGS) $(PM3CXXFLAGS) -Wno-missing-prototypes -Wno-missing-declarations -Wno-missing-field-initializers -c -o $@ $<
$(Q)$(CXX) $(DEPFLAGS) $(PM3CXXFLAGS) -c -o $@ $<
$(Q)$(POSTCOMPILE)
%.o: %.c
@ -808,7 +811,7 @@ $(OBJDIR)/%.o : %.m $(OBJDIR)/%.d
$(Q)$(POSTCOMPILE)
DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(SRCS)) \
$(patsubst %wrap.c, $(OBJDIR)/%.d, $(SWIGSRCS)) \
$(patsubst %wrap.cpp, $(OBJDIR)/%.d, $(SWIGSRCS)) \
$(patsubst %.cpp, $(OBJDIR)/%.d, $(CXXSRCS)) \
$(patsubst %.m, $(OBJDIR)/%.d, $(OBJCSRCS))

View file

@ -1,5 +1,5 @@
#!/bin/bash
cd ..
make src/pm3_luawrap.c
make src/pm3_pywrap.c
make src/pm3_luawrap.cpp
make src/pm3_pywrap.cpp

View file

@ -0,0 +1,5 @@
#!/bin/bash
../../pm3 -c "script run testembedded_cb.py"
# cf https://github.com/swig/swig/tree/master/Examples/python/callback
# cf https://rawgit.com/swig/swig/master/Doc/Manual/SWIGPlus.html#SWIGPlus_target_language_callbacks

View file

@ -0,0 +1,2 @@
http://www.swig.org/Doc4.0/SWIG.html#SWIG_nn30
http://www.swig.org/Doc4.0/SWIGPlus.html#SWIGPlus_target_language_callbacks

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,22 @@
/* File : example.h */
#include <iostream>
class Callback {
public:
virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; }
virtual void run() { std::cout << "Callback::run()" << std::endl; }
};
class Caller {
private:
Callback *_callback;
public:
Caller(): _callback(0) {}
~Caller() { delCallback(); }
void delCallback() { delete _callback; _callback = 0; }
void setCallback(Callback *cb) { delCallback(); _callback = cb; }
void call() { if (_callback) _callback->run(); }
};

View file

@ -0,0 +1,11 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
/* turn on director wrapping Callback */
%feature("director") Callback;
%include "example.h"

View file

@ -0,0 +1,57 @@
# file: runme.py
# This file illustrates the cross language polymorphism using directors.
import example
class PyCallback(example.Callback):
def __init__(self):
example.Callback.__init__(self)
def run(self):
print("PyCallback.run()")
# Create an Caller instance
caller = example.Caller()
# Add a simple C++ callback (caller owns the callback, so
# we disown it first by clearing the .thisown flag).
print("Adding and calling a normal C++ callback")
print("----------------------------------------")
callback = example.Callback()
callback.thisown = 0
caller.setCallback(callback)
caller.call()
caller.delCallback()
print("")
print("Adding and calling a Python callback")
print("------------------------------------")
# Add a Python callback (caller owns the callback, so we
# disown it first by calling __disown__).
caller.setCallback(PyCallback().__disown__())
caller.call()
caller.delCallback()
print("")
print("Adding and calling another Python callback")
print("------------------------------------------")
# Let's do the same but use the weak reference this time.
callback = PyCallback().__disown__()
caller.setCallback(callback)
caller.call()
caller.delCallback()
# All done.
print("")
print("python exit")

View file

@ -0,0 +1,21 @@
#!/usr/bin/env python3
import pm3
p=pm3.pm3()
# PyConsoleHandler class is defined and derived from C++ class ConsoleHandler
class PyConsoleHandler(pm3.ConsoleHandler):
def __init__(self):
pm3.ConsoleHandler.__init__(self)
def handle_output(self, c):
print("PY>>", c, end='')
# don't let original print routine pursuing:
return 0
#p.console("hw status")
handler = PyConsoleHandler()
result = p.console_async_wrapper("hw status", handler)
print(result)
print("Device:", p.name)

View file

@ -1,5 +1,5 @@
#!/bin/bash
cd ..
make src/pm3_luawrap.c
make src/pm3_pywrap.c
make src/pm3_luawrap.cpp
make src/pm3_pywrap.cpp

View file

@ -1,11 +1,26 @@
#ifndef LIBPM3_H
#define LIBPM3_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct pm3_device pm3;
pm3 *pm3_open(char *port);
// not catching output
int pm3_console(pm3 *dev, char *cmd);
// catching output as it comes
int pm3_console_async(pm3 *dev, char *cmd, int (*callback)(char* s));
// catching output at the end
//int pm3_console_sync(pm3 *dev, char *cmd, char* outbuf, int outbufsize);
const char *pm3_name_get(pm3 *dev);
void pm3_close(pm3 *dev);
pm3 *pm3_get_current_dev(void);
#ifdef __cplusplus
}
#endif
#endif // LIBPM3_H

8
client/include/pm3.hpp Normal file
View file

@ -0,0 +1,8 @@
#ifndef LIBPM3PP_H
#define LIBPM3PP_H
#include "pm3.h"
#include "pm3_helper.hpp"
int pm3_console_async_wrapper(pm3 *dev, char *cmd, ConsoleHandler *console_handler);
#endif // LIBPM3PP_H

View file

@ -0,0 +1,10 @@
#ifndef LIBPM3HELPERPP_H
#define LIBPM3HELPERPP_H
class ConsoleHandler {
public:
virtual int handle_output(char *string) = 0;
virtual ~ConsoleHandler() {}
};
#endif // LIBPM3HELPERPP_H

View file

@ -322,6 +322,13 @@ int CommandReceived(char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
int CommandReceivedCB(char *Cmd, print_cb_t callback) {
g_printCallback = callback;
int res = CmdsParse(CommandTable, Cmd);
g_printCallback = NULL;
return res;
}
command_t *getTopLevelCommandTable(void) {
return CommandTable;
}

View file

@ -13,9 +13,18 @@
#include "common.h"
#include "cmdparser.h" // command_t
#include "util.h" // print_cb_t
#ifdef __cplusplus
extern "C" {
#endif
int CommandReceived(char *Cmd);
int CmdRem(const char *Cmd);
command_t *getTopLevelCommandTable(void);
int CommandReceivedCB(char *Cmd, print_cb_t callback);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -2,7 +2,7 @@
// User API
//-----------------------------------------------------------------------------
#include "pm3.h"
#include "pm3.hpp"
#include <stdlib.h>
@ -46,6 +46,23 @@ int pm3_console(pm3_device *dev, char *Cmd) {
return CommandReceived(Cmd);
}
static ConsoleHandler *console_handler_ptr = NULL;
static int console_handler_helper(char *string) {
return console_handler_ptr->handle_output(string);
}
int pm3_console_async_wrapper(pm3_device *dev, char *Cmd, ConsoleHandler *console_handler) {
console_handler_ptr = console_handler;
int result = pm3_console_async(dev, Cmd, &console_handler_helper);
console_handler = NULL; // ?? console_handler_ptr = NULL cf http://www.swig.org/Doc4.0/SWIGPlus.html#SWIGPlus_target_language_callbacks
return result;
}
int pm3_console_async(pm3_device *dev, char *Cmd, int (*callback)(char*)) {
// For now, there is no real device context:
(void) dev;
return CommandReceivedCB(Cmd, callback);
}
const char *pm3_name_get(pm3_device *dev) {
return dev->conn->serial_port_name;
}

View file

@ -1,7 +1,7 @@
%module pm3
%module(directors="1") pm3
%{
/* Include the header in the wrapper code */
#include "pm3.h"
#include "pm3.hpp"
#include "comms.h"
%}
@ -31,9 +31,15 @@ typedef struct {
}
}
int console(char *cmd);
//int console_async(char *cmd, int (*callback)(char*));
int console_async_wrapper(char *cmd, ConsoleHandler *handler);
char const * const name;
}
} pm3;
//%nodefaultctor device;
//%nodefaultdtor device;
/* Parse the header file to generate wrappers */
%feature("director") ConsoleHandler;
%include "../include/pm3_helper.hpp"

View file

@ -61,6 +61,8 @@ class _SwigNonDynamicMeta(type):
__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)
import weakref
class pm3(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
@ -71,10 +73,35 @@ class pm3(object):
def console(self, cmd):
return _pm3.pm3_console(self, cmd)
def console_async_wrapper(self, cmd, handler):
return _pm3.pm3_console_async_wrapper(self, cmd, handler)
name = property(_pm3.pm3_name_get)
# Register pm3 in _pm3:
_pm3.pm3_swigregister(pm3)
class ConsoleHandler(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
def handle_output(self, string):
return _pm3.ConsoleHandler_handle_output(self, string)
__swig_destroy__ = _pm3.delete_ConsoleHandler
def __init__(self):
if self.__class__ == ConsoleHandler:
_self = None
else:
_self = self
_pm3.ConsoleHandler_swiginit(self, _pm3.new_ConsoleHandler(_self, ))
def __disown__(self):
self.this.disown()
_pm3.disown_ConsoleHandler(self)
return weakref.proxy(self)
# Register ConsoleHandler in _pm3:
_pm3.ConsoleHandler_swigregister(ConsoleHandler)

File diff suppressed because it is too large Load diff

3396
client/src/pm3_luawrap.cpp Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

4666
client/src/pm3_pywrap.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -308,6 +308,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
if (logging && session.incognito) {
logging = 0;
}
// TODO log if callback ?
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) {
char *my_logfile_path = NULL;
char filename[40];
@ -367,9 +368,14 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi);
if (g_printAndLog & PRINTANDLOG_PRINT) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), session.emoji_mode);
fprintf(stream, "%s", buffer3);
if (linefeed)
fprintf(stream, "\n");
if (linefeed && (strlen(buffer3) + 1 < sizeof(buffer3)))
buffer3[strlen(buffer3)]='\n';
bool doprint = true;
if (g_printCallback != NULL) {
doprint = g_printCallback(buffer3) != 0;
}
if (doprint)
fprintf(stream, "%s", buffer3);
}
#ifdef RL_STATE_READCMD

View file

@ -30,6 +30,8 @@
uint8_t g_debugMode = 0;
// global client disable logging variable
uint8_t g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
// global client print callback
print_cb_t g_printCallback;
// global client tell if a pending prompt is present
bool g_pendingPrompt = false;

View file

@ -23,6 +23,8 @@
extern uint8_t g_debugMode;
extern uint8_t g_printAndLog;
typedef int (*print_cb_t)(char *s);
extern print_cb_t g_printCallback;
extern bool g_pendingPrompt;
#define PRINTANDLOG_PRINT 1

View file

@ -13,6 +13,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
# include <windows.h>
# define sleep(n) Sleep(1000 *(n))
@ -23,4 +27,7 @@ void msleep(uint32_t n); // sleep n milliseconds
uint64_t msclock(void); // a milliseconds clock
#ifdef __cplusplus
}
#endif
#endif