Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: build

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

jobs:
build:
# 3.9 exercises the pre-3.10 buffer API branch of python/Wiimote.c,
# the other versions the modern one.
name: python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install build dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
libbluetooth-dev flex bison

# setuptools is not bundled with python 3.12+, and setup.py needs it
# since distutils was dropped from the standard library
- name: Install python build dependencies
run: python -m pip install --upgrade pip setuptools

- name: Generate configure
run: aclocal && autoconf

- name: Configure
run: ./configure

- name: Build
run: make

- name: Smoke test
run: |
export LD_LIBRARY_PATH="$PWD/libcwiid"
export PYTHONPATH="$(echo python/build/lib.*)"
python - <<'EOF'
import cwiid

print('loaded', cwiid.__file__)

# the extension exposes the type and the CWIID_* constants
for name in ('BTN_A', 'RPT_BTN', 'MESG_ACC', 'FLAG_MESG_IFC',
'IR_X_MAX'):
assert isinstance(getattr(cwiid, name), int), name

for name in ('close', 'enable', 'disable', 'get_mesg', 'read',
'write', 'send_rpt', 'request_status'):
assert callable(getattr(cwiid.Wiimote, name)), name

# no wiimote here: check the methods are callable and reject a
# closed connection instead of crashing
wiimote = cwiid.Wiimote.__new__(cwiid.Wiimote)
for call in (lambda: wiimote.read(0, 0, 4),
lambda: wiimote.write(0, 0, b'ab'),
lambda: wiimote.send_rpt(0, 0, b'ab'),
lambda: wiimote.close()):
try:
call()
except ValueError as err:
assert 'closed' in str(err), err
else:
raise AssertionError('expected a closed Wiimote error')

print('smoke test ok')
EOF
28 changes: 0 additions & 28 deletions .travis.yml

This file was deleted.

4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2017-03-19 azzra
project
* compatibility with Python 3.10+

2017-03-19 azzra
project
* remove lswm, wmdemo, wminput, wmgui
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# CWiid Wiimote Interface

[![Build Status](https://travis-ci.org/azzra/python3-wiimote.svg?branch=master)](https://travis-ci.org/azzra/python3-wiimote)

## DESCRIPTION

The CWiid package contains the following parts:
Expand All @@ -26,7 +24,7 @@ make
Install the library with package manager & the extension from the sources

```sh
apt-get install libcwiid1
apt install libcwiid1
cd python
sudo make install
```
Expand Down
12 changes: 8 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,19 @@ AC_ARG_WITH(
;;
esac],
[REQUIRE_PYTHON=1; PYTHON_NAME=python3])
if test $REQUIRE_PYTHON; then
if test -n "$REQUIRE_PYTHON"; then
AC_CHECK_PROGS([PYTHON],$PYTHON_NAME)
if test $REQUIRE_PYTHON -a ! $PYTHON; then
if test -z "$PYTHON"; then
AC_MSG_ERROR([$PYTHON_NAME not found])
fi
fi
AC_SUBST(PYTHON)
if test $PYTHON; then
PYTHON_VERSION=[`$PYTHON -c 'import sys; print(sys.version[:3])'`]
if test -n "$PYTHON"; then
dnl sys.version[:3] gives "3.1" for 3.10 and later: ask for the version
dnl fields instead of slicing the version string
AC_MSG_CHECKING([python version])
PYTHON_VERSION=`$PYTHON -c 'import sys; print("%d.%d" % (sys.version_info.major, sys.version_info.minor))'`
AC_MSG_RESULT([$PYTHON_VERSION])
AC_SUBST(PYTHON_VERSION)
AC_DEFINE([HAVE_PYTHON],1,[Define to 1 if python support is enabled])
fi
Expand Down
75 changes: 58 additions & 17 deletions python/Wiimote.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,24 @@
*
*/

/* Must be defined before Python.h: lengths in the '#' argument-parsing
* formats are Py_ssize_t instead of int. Mandatory since python 3.10 --
* always define it, whichever formats are used. */
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#include <errno.h>
#include <stdint.h>
#include <bluetooth/bluetooth.h>
#include <cwiid.h>

/* The old buffer protocol (PyObject_AsWriteBuffer) is deprecated since python
* 3.0 and removed since 3.10: both ways of filling a buffer are kept below,
* selected at compile time so that the module builds against any python 3. */
#if PY_VERSION_HEX < 0x030A0000
#define CWIID_OLD_BUFFER_API 1
#endif

typedef struct {
PyObject_HEAD
cwiid_wiimote_t *wiimote;
Expand Down Expand Up @@ -208,9 +220,11 @@ static int Wiimote_init(Wiimote* self, PyObject* args, PyObject *kwds)
bdaddr = *BDADDR_ANY;
}

if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 5) {
PyEval_InitThreads();
}
#if PY_VERSION_HEX < 0x03070000
/* Deprecated since 3.9, no-op since 3.7: the GIL is always
initialized by Py_Initialize(). */
PyEval_InitThreads();
#endif

Py_BEGIN_ALLOW_THREADS
wiimote = cwiid_open(&bdaddr, flags);
Expand Down Expand Up @@ -758,20 +772,23 @@ static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = { "flags", "report", "buffer", NULL };
unsigned char flags, report;
void *buf;
int len;
Py_buffer buf;
int err;

if (!self->wiimote) {
SET_CLOSED_ERROR;
return NULL;
}

if (!PyArg_ParseTupleAndKeywords(args, kwds, "BBt#:cwiid.Wiimote.send_rpt",
kwlist, &flags, &report, &buf, &len)) {
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"BBy*:cwiid.Wiimote.send_rpt",
kwlist, &flags, &report, &buf)) {
return NULL;
}

if (cwiid_send_rpt(self->wiimote, flags, report, len, buf)) {
err = cwiid_send_rpt(self->wiimote, flags, report, buf.len, buf.buf);
PyBuffer_Release(&buf);
if (err) {
PyErr_SetString(PyExc_RuntimeError, "Error sending report");
return NULL;
}
Expand All @@ -784,9 +801,12 @@ static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = { "flags", "offset", "len", NULL };
unsigned char flags;
unsigned int offset;
Py_ssize_t len;
unsigned int len;
void *buf;
PyObject *pyRetBuf;
#ifdef CWIID_OLD_BUFFER_API
Py_ssize_t buf_len;
#endif

if (!self->wiimote) {
SET_CLOSED_ERROR;
Expand All @@ -798,14 +818,25 @@ static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds)
return NULL;
}

if (!(pyRetBuf = malloc(len))) {
/* cwiid_read takes a uint16_t length: refuse what it cannot fill */
if (len > UINT16_MAX) {
PyErr_SetString(PyExc_ValueError, "len too large");
return NULL;
}

/* mutable buffer, as advertised by the method docstring */
if (!(pyRetBuf = PyByteArray_FromStringAndSize(NULL, len))) {
return NULL;
}
if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &len)) {
#ifdef CWIID_OLD_BUFFER_API
if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &buf_len)) {
Py_DECREF(pyRetBuf);
return NULL;
}
if (cwiid_read(self->wiimote,flags,offset,len,buf)) {
#else
buf = PyByteArray_AS_STRING(pyRetBuf);
#endif
if (cwiid_read(self->wiimote, flags, offset, len, buf)) {
PyErr_SetString(PyExc_RuntimeError, "Error reading wiimote data");
Py_DECREF(pyRetBuf);
return NULL;
Expand All @@ -819,20 +850,30 @@ static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = { "flags", "offset", "buffer", NULL };
unsigned char flags;
unsigned int offset;
void *buf;
int len;
Py_buffer buf;
int err;

if (!self->wiimote) {
SET_CLOSED_ERROR;
return NULL;
}

if (!PyArg_ParseTupleAndKeywords(args, kwds, "BIt#:cwiid.Wiimote.write",
kwlist, &flags, &offset, &buf, &len)) {
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"BIy*:cwiid.Wiimote.write",
kwlist, &flags, &offset, &buf)) {
return NULL;
}

/* cwiid_write takes a uint16_t length: refuse what it cannot send */
if (buf.len > UINT16_MAX) {
PyBuffer_Release(&buf);
PyErr_SetString(PyExc_ValueError, "buffer too large");
return NULL;
}

if (cwiid_write(self->wiimote, flags, offset, len, buf)) {
err = cwiid_write(self->wiimote, flags, offset, buf.len, buf.buf);
PyBuffer_Release(&buf);
if (err) {
PyErr_SetString(PyExc_RuntimeError, "Error writing wiimote data");
return NULL;
}
Expand Down
7 changes: 6 additions & 1 deletion python/setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from distutils.core import setup, Extension
# distutils was removed from the standard library in python 3.12: prefer
# setuptools, fall back to distutils for older pythons without setuptools.
try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension

setup(
name='cwiid',
Expand Down
Loading