Stephen Warren wrote:
> NOTE: This is not the final version of this patch; I'd like to see if I
> can find a simple way to solve the couple of FIXMEs that I added.
> However, I'm submitting it so people can see the direction I'm taking,
> and provide any feedback.

Attached is an updated version that does dump all the parameters. I've
tested "check connectivity", "update configuration", and "update
firmware", all with debug turned off and on, on my 880 using my
in-development version of congruity and libconcord-0.20.

Checkin comment is:

libconcord Python bindings: Implement tracing of all API calls, their
parameters, return values, and any exceptions thrown. Tracing is
requested via an environment variable; see the Python bindings README.

Also, fix the vi formatting commands to match Python syntax.
? concordance/.deps
? concordance/.libs
? concordance/Makefile
? concordance/Makefile.in
? concordance/aclocal.m4
? concordance/autom4te.cache
? concordance/concordance
? concordance/config.guess
? concordance/config.h
? concordance/config.h.in
? concordance/config.log
? concordance/config.status
? concordance/config.sub
? concordance/configure
? concordance/depcomp
? concordance/install-sh
? concordance/libtool
? concordance/ltmain.sh
? concordance/missing
? concordance/stamp-h1
? libconcord/.deps
? libconcord/.libconcord.cpp.swp
? libconcord/.libs
? libconcord/.remote.h.swp
? libconcord/Makefile
? libconcord/Makefile.in
? libconcord/aclocal.m4
? libconcord/autom4te.cache
? libconcord/binaryfile.lo
? libconcord/config.guess
? libconcord/config.h
? libconcord/config.h.in
? libconcord/config.log
? libconcord/config.status
? libconcord/config.sub
? libconcord/configure
? libconcord/depcomp
? libconcord/install-sh
? libconcord/libconcord.la
? libconcord/libconcord.lo
? libconcord/libtool
? libconcord/libusbhid.lo
? libconcord/ltmain.sh
? libconcord/missing
? libconcord/remote.lo
? libconcord/remote_z.lo
? libconcord/stamp-h1
? libconcord/usblan.lo
? libconcord/web.lo
? libconcord/bindings/python/.README.swp
? libconcord/bindings/python/.libconcord.py.swp
? libconcord/bindings/python/build
? libconcord/bindings/python/libconcord.pyc
Index: libconcord/bindings/python/README
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/bindings/python/README,v
retrieving revision 1.1
diff -u -p -r1.1 README
--- libconcord/bindings/python/README	15 Apr 2008 02:34:08 -0000	1.1
+++ libconcord/bindings/python/README	28 Jun 2008 05:42:18 -0000
@@ -32,3 +32,14 @@ the bindings to your PYTHONPATH. For exa
 
 export PYTHONPATH=/path/to/libconcord/bindings/python
 
+Debugging
+====================
+
+If you set the environment variable LIBCONCORD_PY_TRACE to string "1", then
+libconcord.py will trace all function calls. This may prove helpful when
+debugging client applications.
+
+For example, in bash:
+
+LIBCONCORD_PY_TRACE=1 ./congruity /path/to/Connectivity.EZHex
+
Index: libconcord/bindings/python/libconcord.py
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/bindings/python/libconcord.py,v
retrieving revision 1.1
diff -u -p -r1.1 libconcord.py
--- libconcord/bindings/python/libconcord.py	8 Apr 2008 09:50:29 -0000	1.1
+++ libconcord/bindings/python/libconcord.py	28 Jun 2008 05:42:18 -0000
@@ -1,5 +1,5 @@
 #
-# vi: formatoptions+=tc textwidth=80 tabstop=8 shiftwidth=8 noexpandtab:
+# vi: formatoptions+=tc textwidth=80 tabstop=8 shiftwidth=4 expandtab:
 #
 # $Id: libconcord.py,v 1.1 2008/04/08 09:50:29 jaymzh Exp $
 #
@@ -18,19 +18,37 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 #
 
-
 from ctypes import *
 import platform
+import os
 import sys
+import traceback
+
+# Debug request parsing
+
+debug = (os.environ.get("LIBCONCORD_PY_TRACE", "0") == "1")
+
+# Define the libconcord ABI this libconcord.py corresponds to
+# Bump this when the .so file version gets bumped
+
+ABI_VERSION = 0
+
+# Load the DLL
 
-# Internal DLL handle
 if platform.system() == 'Windows':
     _dll = cdll.LoadLibrary('libconcord.dll')
 else:
-    _dll = cdll.LoadLibrary('libconcord.so.0')
+    _dll = cdll.LoadLibrary('libconcord.so.' + str(ABI_VERSION))
+
+# Public libconcord API: Custom types
+
+# typedef void (*lc_callback)(uint32_t, uint32_t, uint32_t, void*);
+callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
+
+# Exception types
 
-# This exception may be raised by any function that returns an LC_ERROR_*.
 class LibConcordException(Exception):
+    """This exception may be raised by any function that returns an LC_ERROR_*."""
     def __init__(self, func, result):
         self.func = func
         self.result = result
@@ -46,7 +64,48 @@ class LibConcordException(Exception):
             repr(self.result_str)
         )
 
+# Helpers for parameter prototyping
+
+class _param(object):
+    def __init__(self, name, ctypes_type):
+        self.name = name
+        self.ctypes_type = ctypes_type
+
+class _in(_param):
+    def real_ctypes_type(self):
+        return self.ctypes_type
+
+class _out(_param):
+    def real_ctypes_type(self):
+        return POINTER(self.ctypes_type)
+
+# Helpers for parameter tracing
+
+def _dump_simple(type):
+    def _dump_simple_imp(value):
+        if not isinstance(value, type):
+            value = type(value)
+        return repr(value.value)
+    return _dump_simple_imp
+
+def _dump_pointer(name):
+    def _dump_pointer_imp(value):
+        return "<<%s @0x%08x>>" % (name, addressof(value))
+    return _dump_pointer_imp
+
+_dumpers = {
+    c_char_p:         _dump_simple(c_char_p),
+    c_int:            _dump_simple(c_int),
+    c_long:           _dump_simple(c_long),
+    c_uint:           _dump_simple(c_uint),
+    c_ulong:          _dump_simple(c_ulong),
+    POINTER(c_ubyte): _dump_pointer('buffer'),
+    callback_type:    _dump_pointer('function'),
+    py_object:        _dump_simple(py_object),
+}
+
 # Internal function result checking functionality
+
 class _CheckRetCode(object):
     def __init__(self, func_name):
         self.func_name = func_name
@@ -55,21 +114,89 @@ class _CheckRetCode(object):
         result = args[0]
         if result != 0:
             raise LibConcordException(self.func_name, result)
-        
+
+# Internal function tracing functionality
+
+_byref_type = type(byref(c_int()))
+def from_param(obj):
+    if type(obj) == _byref_type:
+        return obj._obj
+    if isinstance(obj, _Pointer):
+        return obj.contents
+    raise TypeError, "Output parameters should be byref/pointers"
+
+class _DebugWrapper(object):
+    def __init__(self, callable):
+        self.callable = callable
+
+    def __call__(self, *args):
+        sys.stdout.write("libconcord." + self.callable.__name__ + "(")
+        delim = ""
+        for (val, proto) in zip(args, self.callable._lcpy_protos):
+            if isinstance(proto, _param):
+                name = proto.name
+                if isinstance(proto, _in):
+                    try:
+                        type = proto.ctypes_type
+                        value = _dumpers[type](val)
+                    except:
+                        print traceback.format_exc()
+                        value = "???"
+                else:
+                    value = "<<out>>"
+            else:
+                name = "???"
+                value = "???"
+            sys.stdout.write("%s%s=%s" % (delim, name, value))
+            delim = ", "
+        print ")"
+        try:
+            ret = self.callable(*args)
+            print "    Returned: " + repr(ret)
+            for (val, proto) in zip(args, self.callable._lcpy_protos):
+                if not isinstance(proto, _out):
+                    continue
+                name = proto.name
+                type = proto.ctypes_type
+                try:
+                    value = _dumpers[type](from_param(val))
+                except:
+                    value = "???"
+                print "    <<out>> %s=%s" % (name, value)
+            return ret
+        except:
+            print "    Threw: "
+            s = traceback.format_exc()
+            for sl in s.split('\n'):
+                print "        " + sl
+            raise
+
 # Internal ctypes function wrapper creation
+
 def _create_func(
     func_name,
     error_checker,
-    *args
+    rettype,
+    *protos
 ):
-    ftype = CFUNCTYPE(*args)
+    def real_ctypes_type(type):
+        if not isinstance(type, _param):
+            return type
+        return type.real_ctypes_type()
+    real_protos = [real_ctypes_type(x) for x in protos]
+    ftype = CFUNCTYPE(rettype, *real_protos)
     f = ftype((func_name, _dll))
+    f._lcpy_rettype = rettype
+    f._lcpy_protos = protos
+    f.__name__ = func_name
     if error_checker:
         f.errcheck = error_checker(func_name)
+    if debug:
+        f = _DebugWrapper(f)
+    f.__name__ = func_name
     return f
 
-# typedef void (*lc_callback)(uint32_t, uint32_t, uint32_t, void*);
-callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
+# Public libconcord API: Function prototypes
 
 # const char *get_mfg();
 get_mfg = _create_func(
@@ -241,7 +368,7 @@ get_serial = _create_func(
     'get_serial',
     None,
     c_char_p,
-    c_int
+    _in('p', c_int)
 )
 
 # int get_config_bytes_used();
@@ -326,7 +453,7 @@ delete_block = _create_func(
     'delete_blob',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte)
+    _in('ptr', POINTER(c_ubyte))
 );
 
 LC_FILE_TYPE_CONNECTIVITY  = 0
@@ -339,9 +466,9 @@ identify_file = _create_func(
     'identify_file',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    POINTER(c_int)
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _out('type', c_int)
 )
 
 # int init_concord();
@@ -363,8 +490,8 @@ get_identity = _create_func(
     'get_identity',
     _CheckRetCode,
     c_int,
-    callback_type,
-    py_object
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int reset_remote();
@@ -393,8 +520,8 @@ post_connect_test_success = _create_func
     'post_connect_test_success',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint
+    _in('data', POINTER(c_ubyte)),
+    _in('size', c_uint)
 )
 
 # int post_preconfig(uint8_t *data, uint32_t size);
@@ -402,8 +529,8 @@ post_preconfig = _create_func(
     'post_preconfig',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint
+    _in('data', POINTER(c_ubyte)),
+    _in('size', c_uint)
 )
 
 # int post_postconfig(uint8_t *data, uint32_t size);
@@ -411,8 +538,8 @@ post_postconfig = _create_func(
     'post_postconfig',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint
+    _in('data', POINTER(c_ubyte)),
+    _in('size', c_uint)
 )
 
 # int post_postfirmware(uint8_t *data, uint32_t size);
@@ -420,8 +547,8 @@ post_postfirmware = _create_func(
     'post_postfirmware',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint
+    _in('data', POINTER(c_ubyte)),
+    _in('size', c_uint)
 )
 
 # int invalidate_flash();
@@ -437,10 +564,10 @@ read_config_from_remote = _create_func(
     'read_config_from_remote',
     _CheckRetCode,
     c_int,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_uint),
-    callback_type,
-    py_object
+    _out('out', POINTER(c_ubyte)),
+    _out('size', c_uint),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int write_config_to_remote(uint8_t *in, uint32_t size,
@@ -449,10 +576,10 @@ write_config_to_remote = _create_func(
     'write_config_to_remote',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    callback_type,
-    py_object
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int read_file(char *file_name, uint8_t **out, uint32_t *size);
@@ -460,9 +587,9 @@ read_file = _create_func(
     'read_file',
     _CheckRetCode,
     c_int,
-    c_char_p,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_uint)
+    _in('file_name', c_char_p),
+    _out('out', POINTER(c_ubyte)),
+    _out('size', c_uint)
 )
 
 # int write_config_to_file(uint8_t *in, uint32_t size, char *file_name,
@@ -471,10 +598,10 @@ write_config_to_file = _create_func(
     'write_config_to_file',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    c_char_p,
-    c_int
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('file_name', c_char_p),
+    _in('binary', c_int)
 )
 
 # int verify_remote_config(uint8_t *in, uint32_t size, lc_callback cb,
@@ -483,10 +610,10 @@ verify_remote_config = _create_func(
     'verify_remote_config',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    callback_type,
-    py_object
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int erase_config(uint32_t size, lc_callback cb, void *cb_arg);
@@ -494,9 +621,9 @@ erase_config = _create_func(
     'erase_config',
     _CheckRetCode,
     c_int,
-    c_uint,
-    callback_type,
-    py_object
+    _in('size', c_uint),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int find_config_binary(uint8_t *config, uint32_t config_size,
@@ -505,10 +632,10 @@ find_config_binary = _create_func(
     'find_config_binary',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_uint)
+    _in('config', POINTER(c_ubyte)),
+    _in('config_size', c_uint),
+    _out('binary_ptr', POINTER(c_ubyte)),
+    _out('binary_size', c_uint)
 )
 
 # int erase_safemode(lc_callback cb, void *cb_arg);
@@ -516,8 +643,8 @@ erase_safemode = _create_func(
     'erase_safemode',
     _CheckRetCode,
     c_int,
-    callback_type,
-    py_object
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int read_safemode_from_remote(uint8_t **out, uint32_t *size, lc_callback cb,
@@ -526,20 +653,20 @@ read_safemode_from_remote = _create_func
     'read_safemode_from_remote',
     _CheckRetCode,
     c_int,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_ubyte),
-    callback_type,
-    py_object
+    _out('out', POINTER(c_ubyte)),
+    _out('size', c_ubyte),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
-# int write_safemode_to_file(uint8_t *in, uint32_t size,char *file_name);
+# int write_safemode_to_file(uint8_t *in, uint32_t size, char *file_name);
 write_safemode_to_file = _create_func(
     'write_safemode_to_file',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    c_char_p
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('file_name', c_char_p)
 )
 
 # int is_fw_update_supported(int direct);
@@ -547,7 +674,7 @@ is_fw_update_supported = _create_func(
     'is_fw_update_supported',
     None,
     c_int,
-    c_int
+    _in('direct', c_int)
 )
 
 # int is_config_safe_after_fw();
@@ -576,9 +703,9 @@ erase_firmware = _create_func(
     'erase_firmware',
     _CheckRetCode,
     c_int,
-    c_int,
-    callback_type,
-    py_object
+    _in('direct', c_int),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int read_firmware_from_remote(uint8_t **out, uint32_t *size, lc_callback cb,
@@ -587,10 +714,10 @@ read_firmware_from_remote = _create_func
     'read_firmware_from_remote',
     _CheckRetCode,
     c_int,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_uint),
-    callback_type,
-    py_object
+    _out('out', POINTER(c_ubyte)),
+    _out('size', c_uint),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int write_firmware_to_remote(uint8_t *in, uint32_t size, int direct,
@@ -599,11 +726,11 @@ write_firmware_to_remote = _create_func(
     'write_firmware_to_remote',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    c_int,
-    callback_type,
-    py_object
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('direct', c_int),
+    _in('cb', callback_type),
+    _in('cb_arg', py_object)
 )
 
 # int write_firmware_to_file(uint8_t *in, uint32_t size, char *file_name,
@@ -612,10 +739,10 @@ write_firmware_to_file = _create_func(
     'write_firmware_to_file',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    c_char_p,
-    c_int
+    _in('in', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('file_name', c_char_p),
+    _in('binary', c_int)
 )
 
 # int extract_firmware_binary(uint8_t *xml, uint32_t xml_size, uint8_t **out,
@@ -624,10 +751,10 @@ extract_firmware_binary = _create_func(
     'extract_firmware_binary',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    POINTER(POINTER(c_ubyte)),
-    POINTER(c_uint)
+    _in('xml', POINTER(c_ubyte)),
+    _in('xml_size', c_uint),
+    _out('out', POINTER(c_ubyte)),
+    _out('size', c_uint)
 )
 
 # int learn_ir_commands(uint8_t *data, uint32_t size, int post);
@@ -635,8 +762,8 @@ learn_ir_commands = _create_func(
     'learn_ir_commands',
     _CheckRetCode,
     c_int,
-    POINTER(c_ubyte),
-    c_uint,
-    c_int
+    _in('data', POINTER(c_ubyte)),
+    _in('size', c_uint),
+    _in('post', c_int)
 )
 
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to