From 4f455c60436384c838431b175d3b08df3fbb9086 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Sun, 3 Mar 2024 21:37:08 +0100 Subject: [PATCH] First tiny little steps towards a SWIG "hello world" Config file handling and basic list handling is there. --- CMakeLists.txt | 16 ++++++ src/CMakeLists.txt | 30 ++++++++++- src/libavrdude.i | 122 +++++++++++++++++++++++++++++++++++++++++++++ src/swigtest.py | 61 +++++++++++++++++++++++ 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 src/libavrdude.i create mode 100644 src/swigtest.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 071f50b2..499afebc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,16 @@ if(HAVE_LINUXGPIO) endif() endif() +# ------------------------------------- +# Find SWIG +find_package(SWIG 4.0 COMPONENTS python) +if(SWIG_FOUND) + find_package(PythonLibs REQUIRED) + if(PYTHONLIBS_FOUND) + set(HAVE_SWIG 1) + endif() +endif() + # ===================================== # Use external libraries if requested # ===================================== @@ -424,4 +434,10 @@ else() message(STATUS "DISABLED linuxspi") endif() +if(HAVE_SWIG) + message(STATUS "DO HAVE swig") +else() + message(STATUS "DON'T HAVE swig") +endif() + message(STATUS "----------------------") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c1b9149..f6756926 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -141,7 +141,7 @@ add_custom_target(conf ALL DEPENDS avrdude.conf) # Project # ===================================== -add_library(libavrdude +set(SOURCES ac_cfg.h arduino.h arduino.c @@ -276,6 +276,10 @@ add_library(libavrdude ${EXTRA_WINDOWS_SOURCES} ) +add_library(libavrdude + ${SOURCES} + ) + set_target_properties(libavrdude PROPERTIES PREFIX "" PUBLIC_HEADER "libavrdude.h;libavrdude-avrintel.h" @@ -325,6 +329,30 @@ if(MINGW) target_link_options(avrdude PRIVATE -static) endif() +if(HAVE_SWIG) + include (UseSWIG) + INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/..) + swig_add_library(swig_avrdude LANGUAGE Python SOURCES libavrdude.i ${SOURCES}) + target_link_libraries(swig_avrdude + PRIVATE + ${LIB_MATH} + ${LIB_LIBELF} + ${LIB_LIBUSB} + ${LIB_LIBUSB_1_0} + ${LIB_LIBHID} + ${LIB_LIBHIDAPI} + ${LIB_LIBFTDI} + ${LIB_LIBFTDI1} + ${LIB_LIBREADLINE} + ${LIB_LIBSERIALPORT} + ${LIB_NCURSES} + ${LIB_LIBGPIOD} + ${EXTRA_WINDOWS_LIBRARIES} + ) +endif() + # ===================================== # Install # ===================================== diff --git a/src/libavrdude.i b/src/libavrdude.i new file mode 100644 index 00000000..0c645aa6 --- /dev/null +++ b/src/libavrdude.i @@ -0,0 +1,122 @@ +%module swig_avrdude +%{ +#include "ac_cfg.h" +#include "libavrdude.h" + +// global variables referenced by library +char * version = AVRDUDE_FULL_VERSION; +char * progname = "avrdude"; +char progbuf[] = " "; +int verbose; +int quell_progress; +int ovsigck; +const char *partdesc = ""; +const char *pgmid = ""; + +int avrdude_message(int msglvl, const char *format, ...) +{ + int rc = 0; + va_list ap; + if (verbose >= msglvl) { + va_start(ap, format); + rc = vfprintf(stderr, format, ap); + va_end(ap); + } + return rc; +} + +int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...) { + printf("avrdude_message2() called\n"); + return 0; +} + +PROGRAMMER *cast_programmer(LNODEID p) { + return (PROGRAMMER *)p; +} + +AVRPART *cast_avrpart(LNODEID p) { + return (AVRPART *)p; +} + +AVRMEM *cast_avrmem(LNODEID p) { + return (AVRMEM *)p; +} + +const char *cast_string(LNODEID p) { + return (const char *)p; +} + +%} + +// globals from above are mapped to Python +char * version; +char * progname; +char progbuf[]; +int verbose; +int quell_progress; +int ovsigck; +const char *partdesc; +const char *pgmid; + +typedef void * LNODEID; +typedef void * LISTID; +typedef struct avrmem AVRMEM; + +// These things are read from config file(s), and must be considered +// read-only by any program. Most internals are only relevant for +// libavrdude itself, so only map things to the Python level that are +// needed there. + +%typemap(out) AVRPART* { + PyObject* dict = PyDict_New(); + PyDict_SetItem(dict, PyUnicode_FromString("desc"), + PyUnicode_FromString($1->desc)); + PyDict_SetItem(dict, PyUnicode_FromString("id"), + PyUnicode_FromString($1->id)); + PyDict_SetItem(dict, PyUnicode_FromString("signature"), + PyBytes_FromStringAndSize((const char *)($1->signature), 3)); + PyDict_SetItem(dict, PyUnicode_FromString("mem"), + SWIG_NewPointerObj($1->mem, SWIGTYPE_p_avrmem, 0)); + $result = dict; +} + +%typemap(out) AVRMEM* { + PyObject* dict = PyDict_New(); + PyDict_SetItem(dict, PyUnicode_FromString("desc"), + PyUnicode_FromString($1->desc)); + PyDict_SetItem(dict, PyUnicode_FromString("paged"), + PyBool_FromLong($1->paged)); + PyDict_SetItem(dict, PyUnicode_FromString("size"), + PyLong_FromLong($1->size)); + PyDict_SetItem(dict, PyUnicode_FromString("page_size"), + PyLong_FromLong($1->page_size)); + $result = dict; +} + +// Config file handling +int init_config(void); + +void cleanup_config(void); + +int read_config(const char * file); + +// Lists must not be manipulated from the Python level, so +// only map access functions. +extern LISTID part_list; +extern LISTID programmers; + +LNODEID lfirst ( LISTID ); /* head of the list */ +LNODEID llast ( LISTID ); /* tail of the list */ +LNODEID lnext ( LNODEID ); /* next item in the list */ +LNODEID lprev ( LNODEID ); /* previous item in the list */ +void * ldata ( LNODEID ); /* data at the current position */ +int lsize ( LISTID ); /* number of elements in the list */ + +// Typecast helpers to interpret LNODEID +PROGRAMMER *cast_programmer(LNODEID); + +AVRPART *cast_avrpart(LNODEID); + +AVRMEM *cast_avrmem(LNODEID); + +const char *cast_string(LNODEID); diff --git a/src/swigtest.py b/src/swigtest.py new file mode 100644 index 00000000..73f3ea42 --- /dev/null +++ b/src/swigtest.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# Simple test program for testing the SWIG interface. +# +# Best call this as "python -i src/swigtest.py", +# then run the interactive interpreter. + +# Example: +# a=search_avrpart('m328') +# print(a) +# show_avrmem(a['mem']) + +import sys +import os +import pathlib + +sysname = os.uname()[0].lower() +builddir = f'build_{sysname}/src' + +sys.path.append(builddir) + +import swig_avrdude as ad + +ad.init_config() + +found = False +for d in [builddir, "/etc", "/usr/local/etc"]: + p = pathlib.Path(d + "/avrdude.conf") + if p.is_file(): + print(f"Found avrdude.conf in {d}") + ad.read_config(d + "/avrdude.conf") + found = True + break + +if not found: + print("Sorry, no avrdude.conf could be found.") + sys.exit(1) + +def search_avrpart(name): + '''Search list of AVR parts from config for matching "desc" or "id"''' + + partlist = ad.cvar.part_list + + part = ad.lfirst(partlist) + while part: + d = ad.ldata(part) + avrpart = ad.cast_avrpart(d) + if avrpart['desc'] == name or avrpart['id'] == name: + return avrpart + part = ad.lnext(part) + + return None + +def show_avrmem(mem): + '''List all memories defined at avrpart["mem"]''' + + m = ad.lfirst(mem) + while m: + d = ad.ldata(m) + print(ad.cast_avrmem(d)) + m = ad.lnext(m)