Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readbytesb -- return bytes object for efficiency #80

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ Connects to the specified SPI device, opening `/dev/spidev<bus>.<device>`

readbytes(n)

Read n bytes from SPI device.
Read n bytes from SPI device, returning a list of integers.

readbytesb(n)

Read n bytes from SPI device, returning an (immutable) bytes object (more efficient for larger transfers).

writebytes(list of values)

Expand Down
107 changes: 79 additions & 28 deletions spidev_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,49 +223,97 @@ SpiDev_writebytes(SpiDevObject *self, PyObject *args)
return Py_None;
}

PyDoc_STRVAR(SpiDev_read_doc,
"read(len) -> [values]\n\n"
"Read len bytes from SPI device.\n");

static PyObject *
SpiDev_readbytes(SpiDevObject *self, PyObject *args)
/* return true on success */
static int
SpiDev_read_lowlevel(SpiDevObject *self, uint8_t *buf, int buflen, int lenreq)
{
uint8_t rxbuf[SPIDEV_MAXPATH];
int status, len, ii;
PyObject *list;
int status;

if (!PyArg_ParseTuple(args, "i:read", &len))
return NULL;
/* read at least 1 byte, no more than SPIDEV_MAXPATH */
if (lenreq < 1)
lenreq = 1;
else if ((unsigned)lenreq > sizeof(buflen))
lenreq = buflen;
memset(buf, 0, buflen);

/* read at least 1 byte, no more than SPIDEV_MAXPATH */
if (len < 1)
len = 1;
else if ((unsigned)len > sizeof(rxbuf))
len = sizeof(rxbuf);

memset(rxbuf, 0, sizeof rxbuf);
status = read(self->fd, &rxbuf[0], len);
status = read(self->fd, &buf[0], lenreq);

if (status < 0) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
return 0; // fail
}

if (status != len) {
perror("short read");
return NULL;
if (status != lenreq) {
printf("Short Read: %d/%d bytes\n", status, lenreq);
PyErr_SetString(PyExc_IOError, "SpiDev.read: I/O error: short read.");
return 0; // fail
}
return 1; // succeed
}

list = PyList_New(len);

for (ii = 0; ii < len; ii++) {
PyObject *val = Py_BuildValue("l", (long)rxbuf[ii]);
PyList_SET_ITEM(list, ii, val);
}
#define READBYTES_GENERIC_RESULTTYPE_LIST 0
#define READBYTES_GENERIC_RESULTTYPE_BYTES 1

static PyObject *
SpiDev_readbytes_generic(SpiDevObject *self, PyObject *args, int resultType)
{
static uint8_t rxbuf[SPIDEV_MAXPATH];
int len = 0;

if (!PyArg_ParseTuple(args, "i:read", &len))
return NULL;

// get the bytes here
if (!SpiDev_read_lowlevel(self, rxbuf, sizeof(rxbuf), len)) {
return NULL;
}

return list;
if (resultType == READBYTES_GENERIC_RESULTTYPE_LIST) { // list
int ii;
PyObject *list;
list = PyList_New(len);

for (ii = 0; ii < len; ii++) {
PyObject *val = Py_BuildValue("l", (long)rxbuf[ii]);
PyList_SET_ITEM(list, ii, val);
}

return list;
}
else if (resultType == READBYTES_GENERIC_RESULTTYPE_BYTES) { // bytes
PyObject *bytes;
bytes = Py_BuildValue("y#", rxbuf, len);
return bytes;
}
else { // unknown type
PyErr_SetString(PyExc_RuntimeError, "SpiDev.read: internal problem in readbytes_generic.");
return NULL;
}
}

PyDoc_STRVAR(SpiDev_read_doc,
"read(len) -> [values]\n\n"
"Read len bytes from SPI device, returning a list.\n");

static PyObject *
SpiDev_readbytes(SpiDevObject *self, PyObject *args)
{
return SpiDev_readbytes_generic(self, args, READBYTES_GENERIC_RESULTTYPE_LIST);
}

PyDoc_STRVAR(SpiDev_readb_doc,
"read(len) -> bytes(len)\n\n"
"Read len bytes from SPI device, returning a bytes object of length len.\n");

static PyObject *
SpiDev_readbytesb(SpiDevObject *self, PyObject *args)
{
return SpiDev_readbytes_generic(self, args, READBYTES_GENERIC_RESULTTYPE_BYTES);
}


static PyObject *
SpiDev_writebytes2_buffer(SpiDevObject *self, Py_buffer *buffer)
{
Expand Down Expand Up @@ -861,6 +909,7 @@ SpiDev_xfer3(SpiDevObject *self, PyObject *args)
return rx_tuple;
}


static int __spidev_set_mode( int fd, __u8 mode) {
__u8 test;
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
Expand Down Expand Up @@ -1365,6 +1414,8 @@ static PyMethodDef SpiDev_methods[] = {
SpiDev_fileno_doc},
{"readbytes", (PyCFunction)SpiDev_readbytes, METH_VARARGS,
SpiDev_read_doc},
{"readbytesb", (PyCFunction)SpiDev_readbytesb, METH_VARARGS,
SpiDev_readb_doc},
{"writebytes", (PyCFunction)SpiDev_writebytes, METH_VARARGS,
SpiDev_write_doc},
{"writebytes2", (PyCFunction)SpiDev_writebytes2, METH_VARARGS,
Expand Down