diff --git a/library/rpi_ws281x.i b/library/rpi_ws281x.i index f362345..bc73bbb 100644 --- a/library/rpi_ws281x.i +++ b/library/rpi_ws281x.i @@ -1,6 +1,8 @@ // SWIG interface file to define rpi_ws281x library python wrapper. // Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net) +%nothread; + // Define module name rpi_ws281x. This will actually be imported under // the name _rpi_ws281x following the SWIG & Python conventions. %module rpi_ws281x @@ -92,3 +94,12 @@ static int convert_iarray(PyObject *input, uint8_t *ptr, int size) { return &ws->channel[channelnum]; } %} + +%thread; +%inline %{ + ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811) + { + return ws2811_render(ws2811); + } +%} +%nothread; diff --git a/library/rpi_ws281x.py b/library/rpi_ws281x.py index 2761371..25f04c7 100644 --- a/library/rpi_ws281x.py +++ b/library/rpi_ws281x.py @@ -5,7 +5,6 @@ # the SWIG interface file instead. from sys import version_info as _swig_python_version_info - if _swig_python_version_info < (2, 7, 0): raise RuntimeError("Python 2.7 or later required") @@ -20,17 +19,12 @@ except ImportError: import __builtin__ - def _swig_repr(self): try: strthis = "proxy of " + self.this.__repr__() except __builtin__.Exception: strthis = "" - return "<%s.%s; %s >" % ( - self.__class__.__module__, - self.__class__.__name__, - strthis, - ) + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) def _swig_setattr_nondynamic_instance_variable(set): @@ -43,7 +37,6 @@ def set_instance_attr(self, name, value): set(self, name, value) else: raise AttributeError("You cannot add instance attributes to %s" % self) - return set_instance_attr @@ -53,22 +46,18 @@ def set_class_attr(cls, name, value): set(cls, name, value) else: raise AttributeError("You cannot add class attributes to %s" % cls) - return set_class_attr def _swig_add_metaclass(metaclass): """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass""" - def wrapper(cls): return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) - return wrapper class _SwigNonDynamicMeta(type): """Meta class to enforce nondynamic attributes (no new attributes) for a class""" - __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__) @@ -89,83 +78,42 @@ class _SwigNonDynamicMeta(type): WS2812_STRIP = _rpi_ws281x.WS2812_STRIP SK6812_STRIP = _rpi_ws281x.SK6812_STRIP SK6812W_STRIP = _rpi_ws281x.SK6812W_STRIP - - class ws2811_channel_t(object): - thisown = property( - lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag" - ) + thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag") __repr__ = _swig_repr - gpionum = property( - _rpi_ws281x.ws2811_channel_t_gpionum_get, - _rpi_ws281x.ws2811_channel_t_gpionum_set, - ) - invert = property( - _rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set - ) - count = property( - _rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set - ) - strip_type = property( - _rpi_ws281x.ws2811_channel_t_strip_type_get, - _rpi_ws281x.ws2811_channel_t_strip_type_set, - ) - leds = property( - _rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set - ) - brightness = property( - _rpi_ws281x.ws2811_channel_t_brightness_get, - _rpi_ws281x.ws2811_channel_t_brightness_set, - ) - wshift = property( - _rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set - ) - rshift = property( - _rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set - ) - gshift = property( - _rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set - ) - bshift = property( - _rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set - ) - gamma = property( - _rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set - ) + gpionum = property(_rpi_ws281x.ws2811_channel_t_gpionum_get, _rpi_ws281x.ws2811_channel_t_gpionum_set) + invert = property(_rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set) + count = property(_rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set) + strip_type = property(_rpi_ws281x.ws2811_channel_t_strip_type_get, _rpi_ws281x.ws2811_channel_t_strip_type_set) + leds = property(_rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set) + brightness = property(_rpi_ws281x.ws2811_channel_t_brightness_get, _rpi_ws281x.ws2811_channel_t_brightness_set) + wshift = property(_rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set) + rshift = property(_rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set) + gshift = property(_rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set) + bshift = property(_rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set) + gamma = property(_rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set) def __init__(self): _rpi_ws281x.ws2811_channel_t_swiginit(self, _rpi_ws281x.new_ws2811_channel_t()) - __swig_destroy__ = _rpi_ws281x.delete_ws2811_channel_t - # Register ws2811_channel_t in _rpi_ws281x: _rpi_ws281x.ws2811_channel_t_swigregister(ws2811_channel_t) - class ws2811_t(object): - thisown = property( - lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag" - ) + thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag") __repr__ = _swig_repr - render_wait_time = property( - _rpi_ws281x.ws2811_t_render_wait_time_get, - _rpi_ws281x.ws2811_t_render_wait_time_set, - ) + render_wait_time = property(_rpi_ws281x.ws2811_t_render_wait_time_get, _rpi_ws281x.ws2811_t_render_wait_time_set) device = property(_rpi_ws281x.ws2811_t_device_get, _rpi_ws281x.ws2811_t_device_set) rpi_hw = property(_rpi_ws281x.ws2811_t_rpi_hw_get, _rpi_ws281x.ws2811_t_rpi_hw_set) freq = property(_rpi_ws281x.ws2811_t_freq_get, _rpi_ws281x.ws2811_t_freq_set) dmanum = property(_rpi_ws281x.ws2811_t_dmanum_get, _rpi_ws281x.ws2811_t_dmanum_set) - channel = property( - _rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set - ) + channel = property(_rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set) def __init__(self): _rpi_ws281x.ws2811_t_swiginit(self, _rpi_ws281x.new_ws2811_t()) - __swig_destroy__ = _rpi_ws281x.delete_ws2811_t - # Register ws2811_t in _rpi_ws281x: _rpi_ws281x.ws2811_t_swigregister(ws2811_t) @@ -186,38 +134,34 @@ def __init__(self): WS2811_ERROR_SPI_TRANSFER = _rpi_ws281x.WS2811_ERROR_SPI_TRANSFER WS2811_RETURN_STATE_COUNT = _rpi_ws281x.WS2811_RETURN_STATE_COUNT - def ws2811_init(ws2811): return _rpi_ws281x.ws2811_init(ws2811) - def ws2811_fini(ws2811): return _rpi_ws281x.ws2811_fini(ws2811) - def ws2811_render(ws2811): return _rpi_ws281x.ws2811_render(ws2811) - def ws2811_wait(ws2811): return _rpi_ws281x.ws2811_wait(ws2811) - def ws2811_get_return_t_str(state): return _rpi_ws281x.ws2811_get_return_t_str(state) - def ws2811_set_custom_gamma_factor(ws2811, gamma_factor): return _rpi_ws281x.ws2811_set_custom_gamma_factor(ws2811, gamma_factor) - def ws2811_led_get(channel, lednum): return _rpi_ws281x.ws2811_led_get(channel, lednum) - def ws2811_led_set(channel, lednum, color): return _rpi_ws281x.ws2811_led_set(channel, lednum, color) - def ws2811_channel_get(ws, channelnum): return _rpi_ws281x.ws2811_channel_get(ws, channelnum) + +def ws2811_render_nogil(ws2811): + return _rpi_ws281x.ws2811_render_nogil(ws2811) + + diff --git a/library/rpi_ws281x/rpi_ws281x.py b/library/rpi_ws281x/rpi_ws281x.py index f9d6a8a..1aa2489 100644 --- a/library/rpi_ws281x/rpi_ws281x.py +++ b/library/rpi_ws281x/rpi_ws281x.py @@ -149,6 +149,13 @@ def show(self): str_resp = ws.ws2811_get_return_t_str(resp) raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp)) + def show_nogil(self): + """Update the display with the data from the LED buffer, with no Global-Interpreter-Lock.""" + resp = ws.ws2811_render_nogil(self._leds) + if resp != 0: + str_resp = ws.ws2811_get_return_t_str(resp) + raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp)) + def setPixelColor(self, n, color): """Set LED at position n to the provided 24-bit color value (in RGB order). """ diff --git a/library/rpi_ws281x_wrap.c b/library/rpi_ws281x_wrap.c index 10959fe..f9bbc61 100644 --- a/library/rpi_ws281x_wrap.c +++ b/library/rpi_ws281x_wrap.c @@ -13,6 +13,7 @@ #define SWIGPYTHON #endif +#define SWIG_PYTHON_THREADS #define SWIG_PYTHON_DIRECTOR_NO_VTABLE /* ----------------------------------------------------------------------------- @@ -3132,6 +3133,12 @@ SWIG_FromCharPtr(const char *cptr) return &ws->channel[channelnum]; } + + ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811) + { + return ws2811_render(ws2811); + } + #ifdef __cplusplus extern "C" { #endif @@ -4370,6 +4377,33 @@ SWIGINTERN PyObject *_wrap_ws2811_channel_get(PyObject *SWIGUNUSEDPARM(self), Py } +SWIGINTERN PyObject *_wrap_ws2811_render_nogil(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + ws2811_t *arg1 = (ws2811_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + ws2811_return_t result; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ws2811_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ws2811_render_nogil" "', argument " "1"" of type '" "ws2811_t *""'"); + } + arg1 = (ws2811_t *)(argp1); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = (ws2811_return_t)ws2811_render_nogil(arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + static PyMethodDef SwigMethods[] = { { "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL}, { "ws2811_channel_t_gpionum_set", _wrap_ws2811_channel_t_gpionum_set, METH_VARARGS, NULL}, @@ -4423,6 +4457,7 @@ static PyMethodDef SwigMethods[] = { { "ws2811_led_get", _wrap_ws2811_led_get, METH_VARARGS, NULL}, { "ws2811_led_set", _wrap_ws2811_led_set, METH_VARARGS, NULL}, { "ws2811_channel_get", _wrap_ws2811_channel_get, METH_VARARGS, NULL}, + { "ws2811_render_nogil", _wrap_ws2811_render_nogil, METH_O, NULL}, { NULL, NULL, 0, NULL } }; @@ -5263,6 +5298,9 @@ SWIG_init(void) { SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_SETUP",SWIG_From_int((int)(WS2811_ERROR_SPI_SETUP))); SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_TRANSFER",SWIG_From_int((int)(WS2811_ERROR_SPI_TRANSFER))); SWIG_Python_SetConstant(d, "WS2811_RETURN_STATE_COUNT",SWIG_From_int((int)(WS2811_RETURN_STATE_COUNT))); + + /* Initialize threading */ + SWIG_PYTHON_INITIALIZE_THREADS; #if PY_VERSION_HEX >= 0x03000000 return m; #else