From 858c3f696cf24635b81bfb739452985df1ac44af Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Mon, 18 Mar 2024 20:57:17 +0100 Subject: [PATCH] Add an update_progress implementation This allows for Python code providing a callback function that is used to indicate progress. Also fix a few minor things in message callback (reference counting of Python objects). --- src/libavrdude.i | 41 ++++++++++++++++++++++++++++++++++++----- src/swigtest.py | 10 ++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/libavrdude.i b/src/libavrdude.i index 1772b77f..9d4b81a5 100644 --- a/src/libavrdude.i +++ b/src/libavrdude.i @@ -35,12 +35,35 @@ const char *partdesc = ""; const char *pgmid = ""; static PyObject *msg_cb = NULL; +static PyObject *progress_cb = NULL; +static void swig_progress(int percent, double etime, const char *hdr, int finish); void set_msg_callback(PyObject *PyFunc) { - if (PyFunc == Py_None) + if (PyFunc == Py_None) { + if (msg_cb) + Py_XDECREF(msg_cb); // Remove reference to previous callback msg_cb = NULL; - else + } else { + if (msg_cb) + Py_XDECREF(msg_cb); // Remove reference to previous callback + Py_XINCREF(PyFunc); // Add reference to new callback msg_cb = PyFunc; + } +} + +void set_progress_callback(PyObject *PyFunc) { + if (PyFunc == Py_None) { + if (progress_cb) + Py_XDECREF(progress_cb); // Remove reference to previous callback + update_progress = NULL; + progress_cb = NULL; + } else { + if (progress_cb) + Py_XDECREF(progress_cb); // Remove reference to previous callback + progress_cb = PyFunc; + Py_XINCREF(PyFunc); // Add reference to new callback + update_progress = swig_progress; + } } // We cannot pass va_args to Python, so pre-process the message here @@ -92,8 +115,6 @@ int avrdude_message2(FILE *fp, int lno, const char *file, PyObject *result = PyObject_CallFunction(msg_cb, "(sissiis)", target, lno, file, func, msgmode, msglvl, p); Py_XDECREF(result); - } else { - fprintf(stderr, "Would call msg callback here\n"); } free(p); } @@ -101,6 +122,15 @@ int avrdude_message2(FILE *fp, int lno, const char *file, return rc; } +static void swig_progress(int percent, double etime, const char *hdr, int finish) +{ + if (progress_cb) { + PyObject *result = + PyObject_CallFunction(progress_cb, "(idsi)", percent, etime, hdr, finish); + Py_XDECREF(result); + } +} + PROGRAMMER *ldata_programmer(LNODEID p) { return (PROGRAMMER *)ldata(p); } @@ -161,7 +191,7 @@ enum msgmode { MSG2_FLUSH = 64, // Flush before and after printing }; -// Function to record a callback +// Functions to record a callback %typemap(in) PyObject *PyFunc { // calling with None removes previous callback if ($input != Py_None && !PyCallable_Check($input)) { @@ -171,6 +201,7 @@ enum msgmode { $1 = $input; } void set_msg_callback(PyObject *PyFunc); +void set_progress_callback(PyObject *PyFunc); // These things are read from config file(s), and must be considered // read-only by any program. Most internals are only relevant for diff --git a/src/swigtest.py b/src/swigtest.py index d313323f..01f89821 100644 --- a/src/swigtest.py +++ b/src/swigtest.py @@ -10,6 +10,7 @@ # getavr("m128") # ad.set_msg_callback(msg_callback) +# ad.set_progress_callback(progress_callback) # ad.cvar.verbose=2 # p = ad.locate_part(ad.cvar.part_list, 'm168pb') # ad.avr_initmem(p) @@ -178,3 +179,12 @@ def msg_callback(target: str, lno: int, fname: str, func: str, s += msg print(s, end='') +# very simplified progress callback +global prog_hdr +def progress_callback(percent: int, etime: float, hdr: str, finish: int): + if hdr: + global prog_hdr + prog_hdr = hdr + print(f"{prog_hdr} {percent:3d} %", end='\r', file=sys.stderr, flush=True) + if (percent == 100): + print("", file=sys.stderr)