├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── pyproject.toml ├── setup.cfg ├── setup.py └── spidev_module.c /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | dist/ 4 | sdist/ 5 | env/ 6 | build/ 7 | develop-eggs/ 8 | eggs/ 9 | *.egg-info/ 10 | .installed.cfg 11 | *.egg 12 | 13 | pip-log.txt 14 | pip-delete-this-directory.txt 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | --------- 3 | 4 | 3.6 5 | ==== 6 | 7 | * Added read0 flag to enable reading 0 bytes after transfer to lower CS when cshigh == True 8 | 9 | 3.5 10 | ==== 11 | 12 | * Fixed memory leaks 13 | 14 | 3.4 15 | ===== 16 | 17 | * Changed license to MIT 18 | 19 | 3.0.1 20 | ===== 21 | 22 | * Fixed README.md and CHANGELOG.md formatting, hopefully 23 | 24 | 3.0 25 | === 26 | 27 | * Memset fix recommended by Dougie Lawson 28 | * Fixes for Kernel 3.15+ from https://github.com/chrillomat/py-spidev 29 | * Fixes for Python 3/2 compatibility. 30 | * Added subclassing support - https://github.com/doceme/py-spidev/issues/10 31 | 32 | 2.0 33 | === 34 | 35 | Code sourced from http://elk.informatik.fh-augsburg.de/da/da-49/trees/pyap7k/lang/py-spi 36 | and modified. 37 | 38 | Pre 2.0 39 | ======= 40 | 41 | spimodule.c originally uathored by Volker Thoms, 2009. 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Stephen Caudle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include spidev_module.c 2 | include README.md 3 | include CHANGELOG.md 4 | include LICENSE 5 | include setup.py 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: dist upload-test upload clean cleardir distclean 2 | 3 | PYTHON ?= python 4 | TWINE ?= twine 5 | 6 | all: 7 | $(PYTHON) setup.py build 8 | 9 | install: 10 | $(PYTHON) setup.py install 11 | 12 | upload-test: 13 | $(TWINE) upload --repository-url https://test.pypi.org/legacy/ dist/* 14 | 15 | upload: 16 | $(TWINE) upload dist/* 17 | 18 | dist: 19 | $(PYTHON) setup.py sdist 20 | $(PYTHON) setup.py bdist_wheel 21 | 22 | clean: 23 | $(PYTHON) setup.py clean 24 | rm -rf build dist 25 | 26 | cleandir distclean: clean 27 | $(PYTHON) setup.py clean -a 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python Spidev 2 | ============= 3 | 4 | This project contains a python module for interfacing with SPI devices from user space via the spidev linux kernel driver. 5 | 6 | All code is MIT licensed unless explicitly stated otherwise. 7 | 8 | Usage 9 | ----- 10 | 11 | ```python 12 | import spidev 13 | spi = spidev.SpiDev() 14 | spi.open(bus, device) 15 | to_send = [0x01, 0x02, 0x03] 16 | spi.xfer(to_send) 17 | ``` 18 | Settings 19 | -------- 20 | 21 | ```python 22 | import spidev 23 | spi = spidev.SpiDev() 24 | spi.open(bus, device) 25 | 26 | # Settings (for example) 27 | spi.max_speed_hz = 5000 28 | spi.mode = 0b01 29 | 30 | ... 31 | ``` 32 | 33 | * `bits_per_word` 34 | * `cshigh` 35 | * `loop` - Set the "SPI_LOOP" flag to enable loopback mode 36 | * `no_cs` - Set the "SPI_NO_CS" flag to disable use of the chip select (although the driver may still own the CS pin) 37 | * `lsbfirst` 38 | * `max_speed_hz` 39 | * `mode` - SPI mode as two bit pattern of clock polarity and phase [CPOL|CPHA], min: 0b00 = 0, max: 0b11 = 3 40 | * `threewire` - SI/SO signals shared 41 | * `read0` - Read 0 bytes after transfer to lower CS if cshigh == True 42 | 43 | Methods 44 | ------- 45 | 46 | open(bus, device) 47 | 48 | Connects to the specified SPI device, opening `/dev/spidev.` 49 | 50 | readbytes(n) 51 | 52 | Read n bytes from SPI device. 53 | 54 | writebytes(list of values) 55 | 56 | Writes a list of values to SPI device. 57 | 58 | writebytes2(list of values) 59 | 60 | Similar to `writebytes` but accepts arbitrary large lists. 61 | If list size exceeds buffer size (which is read from `/sys/module/spidev/parameters/bufsiz`), 62 | data will be split into smaller chunks and sent in multiple operations. 63 | 64 | Also, `writebytes2` understands [buffer protocol](https://docs.python.org/3/c-api/buffer.html) 65 | so it can accept numpy byte arrays for example without need to convert them with `tolist()` first. 66 | This offers much better performance where you need to transfer frames to SPI-connected displays for instance. 67 | 68 | xfer(list of values[, speed_hz, delay_usec, bits_per_word]) 69 | 70 | Performs an SPI transaction. Chip-select should be released and reactivated between blocks. 71 | Delay specifies the delay in usec between blocks. 72 | 73 | xfer2(list of values[, speed_hz, delay_usec, bits_per_word]) 74 | 75 | Performs an SPI transaction. Chip-select should be held active between blocks. 76 | 77 | xfer3(list of values[, speed_hz, delay_usec, bits_per_word]) 78 | 79 | Similar to `xfer2` but accepts arbitrary large lists. 80 | If list size exceeds buffer size (which is read from `/sys/module/spidev/parameters/bufsiz`), 81 | data will be split into smaller chunks and sent in multiple operations. 82 | 83 | close() 84 | 85 | Disconnects from the SPI device. 86 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description_file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup, Extension 4 | 5 | version = "0.0" 6 | 7 | lines = [x for x in open("spidev_module.c").read().split("\n") if "#define" in x and "_VERSION_" in x and "\"" in x] 8 | 9 | if len(lines) > 0: 10 | version = lines[0].split("\"")[1] 11 | else: 12 | raise Exception("Unable to find _VERSION_ in spidev_module.c") 13 | 14 | 15 | classifiers = ['Development Status :: 5 - Production/Stable', 16 | 'Operating System :: POSIX :: Linux', 17 | 'License :: OSI Approved :: MIT License', 18 | 'Intended Audience :: Developers', 19 | 'Programming Language :: Python :: 2.6', 20 | 'Programming Language :: Python :: 2.7', 21 | 'Programming Language :: Python :: 3', 22 | 'Topic :: Software Development', 23 | 'Topic :: System :: Hardware', 24 | 'Topic :: System :: Hardware :: Hardware Drivers'] 25 | 26 | setup( name = "spidev", 27 | version = version, 28 | description = "Python bindings for Linux SPI access through spidev", 29 | long_description= open('README.md').read() + "\n" + open('CHANGELOG.md').read(), 30 | long_description_content_type = "text/markdown", 31 | author = "Volker Thoms", 32 | author_email = "unconnected@gmx.de", 33 | maintainer = "Stephen Caudle", 34 | maintainer_email= "scaudle@doceme.com", 35 | license = "MIT", 36 | classifiers = classifiers, 37 | url = "http://github.com/doceme/py-spidev", 38 | ext_modules = [Extension("spidev", ["spidev_module.c"])] 39 | ) 40 | -------------------------------------------------------------------------------- /spidev_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * spidev_module.c - Python bindings for Linux SPI access through spidev 3 | * 4 | * MIT License 5 | * 6 | * Copyright (C) 2009 Volker Thoms 7 | * Copyright (C) 2012 Stephen Caudle 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include 29 | #include "structmember.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #define _VERSION_ "3.7" 39 | #define SPIDEV_MAXPATH 4096 40 | 41 | #define BLOCK_SIZE_CONTROL_FILE "/sys/module/spidev/parameters/bufsiz" 42 | // The xfwr3 function attempts to use large blocks if /sys/module/spidev/parameters/bufsiz setting allows it. 43 | // However where we cannot get a value from that file, we fall back to this safe default. 44 | #define XFER3_DEFAULT_BLOCK_SIZE SPIDEV_MAXPATH 45 | // Largest block size for xfer3 - even if /sys/module/spidev/parameters/bufsiz allows bigger 46 | // blocks, we won't go above this value. As I understand, DMA is not used for anything bigger so why bother. 47 | #define XFER3_MAX_BLOCK_SIZE 65535 48 | 49 | 50 | #if PY_MAJOR_VERSION < 3 51 | #define PyLong_AS_LONG(val) PyInt_AS_LONG(val) 52 | #define PyLong_AsLong(val) PyInt_AsLong(val) 53 | #endif 54 | 55 | // Macros needed for Python 3 56 | #ifndef PyInt_Check 57 | #define PyInt_Check PyLong_Check 58 | #define PyInt_FromLong PyLong_FromLong 59 | #define PyInt_AsLong PyLong_AsLong 60 | #define PyInt_Type PyLong_Type 61 | #endif 62 | 63 | // Maximum block size for xfer3 64 | // Initialised once by get_xfer3_block_size 65 | uint32_t xfer3_block_size = 0; 66 | 67 | // Read maximum block size from the /sys/module/spidev/parameters/bufsiz 68 | // In case of any problems reading the number, we fall back to XFER3_DEFAULT_BLOCK_SIZE. 69 | // If number is read ok but it exceeds the XFER3_MAX_BLOCK_SIZE, it will be capped to that value. 70 | // The value is read and cached on the first invocation. Following invocations just return the cached one. 71 | uint32_t get_xfer3_block_size(void) { 72 | int value; 73 | 74 | // If value was already initialised, just use it 75 | if (xfer3_block_size != 0) { 76 | return xfer3_block_size; 77 | } 78 | 79 | // Start with the default 80 | xfer3_block_size = XFER3_DEFAULT_BLOCK_SIZE; 81 | 82 | FILE *file = fopen(BLOCK_SIZE_CONTROL_FILE,"r"); 83 | if (file != NULL) { 84 | if (fscanf(file, "%d", &value) == 1 && value > 0) { 85 | if (value <= XFER3_MAX_BLOCK_SIZE) { 86 | xfer3_block_size = value; 87 | } else { 88 | xfer3_block_size = XFER3_MAX_BLOCK_SIZE; 89 | } 90 | } 91 | fclose(file); 92 | } 93 | 94 | return xfer3_block_size; 95 | } 96 | 97 | PyDoc_STRVAR(SpiDev_module_doc, 98 | "This module defines an object type that allows SPI transactions\n" 99 | "on hosts running the Linux kernel. The host kernel must have SPI\n" 100 | "support and SPI device interface support.\n" 101 | "All of these can be either built-in to the kernel, or loaded from\n" 102 | "modules.\n" 103 | "\n" 104 | "Because the SPI device interface is opened R/W, users of this\n" 105 | "module usually must have root permissions.\n"); 106 | 107 | typedef struct { 108 | PyObject_HEAD 109 | 110 | int fd; /* open file descriptor: /dev/spidevX.Y */ 111 | uint8_t mode; /* current SPI mode */ 112 | uint8_t bits_per_word; /* current SPI bits per word setting */ 113 | uint32_t max_speed_hz; /* current SPI max speed setting in Hz */ 114 | uint8_t read0; /* read 0 bytes after transfer to lwoer CS if SPI_CS_HIGH */ 115 | } SpiDevObject; 116 | 117 | static PyObject * 118 | SpiDev_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 119 | { 120 | SpiDevObject *self; 121 | if ((self = (SpiDevObject *)type->tp_alloc(type, 0)) == NULL) 122 | return NULL; 123 | 124 | self->fd = -1; 125 | self->mode = 0; 126 | self->bits_per_word = 0; 127 | self->max_speed_hz = 0; 128 | 129 | Py_INCREF(self); 130 | return (PyObject *)self; 131 | } 132 | 133 | PyDoc_STRVAR(SpiDev_close_doc, 134 | "close()\n\n" 135 | "Disconnects the object from the interface.\n"); 136 | 137 | static PyObject * 138 | SpiDev_close(SpiDevObject *self) 139 | { 140 | if ((self->fd != -1) && (close(self->fd) == -1)) { 141 | PyErr_SetFromErrno(PyExc_IOError); 142 | return NULL; 143 | } 144 | 145 | self->fd = -1; 146 | self->mode = 0; 147 | self->bits_per_word = 0; 148 | self->max_speed_hz = 0; 149 | 150 | Py_INCREF(Py_None); 151 | return Py_None; 152 | } 153 | 154 | static void 155 | SpiDev_dealloc(SpiDevObject *self) 156 | { 157 | PyObject *ref = SpiDev_close(self); 158 | Py_XDECREF(ref); 159 | 160 | Py_TYPE(self)->tp_free((PyObject *)self); 161 | } 162 | 163 | static char *wrmsg_list0 = "Empty argument list."; 164 | static char *wrmsg_listmax = "Argument list size exceeds %d bytes."; 165 | static char *wrmsg_val = "Non-Int/Long value in arguments: %x."; 166 | static char *wrmsg_oom = "Out of memory."; 167 | 168 | 169 | PyDoc_STRVAR(SpiDev_write_doc, 170 | "write([values]) -> None\n\n" 171 | "Write bytes to SPI device.\n"); 172 | 173 | static PyObject * 174 | SpiDev_writebytes(SpiDevObject *self, PyObject *args) 175 | { 176 | int status; 177 | uint16_t ii, len; 178 | uint8_t buf[SPIDEV_MAXPATH]; 179 | PyObject *obj; 180 | PyObject *seq; 181 | char wrmsg_text[4096]; 182 | 183 | if (!PyArg_ParseTuple(args, "O:write", &obj)) 184 | return NULL; 185 | 186 | seq = PySequence_Fast(obj, "expected a sequence"); 187 | len = PySequence_Fast_GET_SIZE(seq); 188 | if (!seq || len <= 0) { 189 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 190 | return NULL; 191 | } 192 | 193 | if (len > SPIDEV_MAXPATH) { 194 | snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_listmax, SPIDEV_MAXPATH); 195 | PyErr_SetString(PyExc_OverflowError, wrmsg_text); 196 | return NULL; 197 | } 198 | 199 | for (ii = 0; ii < len; ii++) { 200 | PyObject *val = PySequence_Fast_GET_ITEM(seq, ii); 201 | #if PY_MAJOR_VERSION < 3 202 | if (PyInt_Check(val)) { 203 | buf[ii] = (__u8)PyInt_AS_LONG(val); 204 | } else 205 | #endif 206 | { 207 | if (PyLong_Check(val)) { 208 | buf[ii] = (__u8)PyLong_AS_LONG(val); 209 | } else { 210 | snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val); 211 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 212 | return NULL; 213 | } 214 | } 215 | } 216 | 217 | Py_DECREF(seq); 218 | 219 | status = write(self->fd, &buf[0], len); 220 | 221 | if (status < 0) { 222 | PyErr_SetFromErrno(PyExc_IOError); 223 | return NULL; 224 | } 225 | 226 | if (status != len) { 227 | perror("short write"); 228 | return NULL; 229 | } 230 | 231 | Py_INCREF(Py_None); 232 | return Py_None; 233 | } 234 | 235 | PyDoc_STRVAR(SpiDev_read_doc, 236 | "read(len) -> [values]\n\n" 237 | "Read len bytes from SPI device.\n"); 238 | 239 | static PyObject * 240 | SpiDev_readbytes(SpiDevObject *self, PyObject *args) 241 | { 242 | uint8_t rxbuf[SPIDEV_MAXPATH]; 243 | int status, len, ii; 244 | PyObject *list; 245 | 246 | if (!PyArg_ParseTuple(args, "i:read", &len)) 247 | return NULL; 248 | 249 | /* read at least 1 byte, no more than SPIDEV_MAXPATH */ 250 | if (len < 1) 251 | len = 1; 252 | else if ((unsigned)len > sizeof(rxbuf)) 253 | len = sizeof(rxbuf); 254 | 255 | memset(rxbuf, 0, sizeof rxbuf); 256 | status = read(self->fd, &rxbuf[0], len); 257 | 258 | if (status < 0) { 259 | PyErr_SetFromErrno(PyExc_IOError); 260 | return NULL; 261 | } 262 | 263 | if (status != len) { 264 | perror("short read"); 265 | return NULL; 266 | } 267 | 268 | list = PyList_New(len); 269 | 270 | for (ii = 0; ii < len; ii++) { 271 | PyObject *val = PyLong_FromLong((long)rxbuf[ii]); 272 | PyList_SET_ITEM(list, ii, val); // Steals reference, no need to Py_DECREF(val) 273 | } 274 | 275 | return list; 276 | } 277 | 278 | static PyObject * 279 | SpiDev_writebytes2_buffer(SpiDevObject *self, Py_buffer *buffer) 280 | { 281 | int status; 282 | Py_ssize_t remain, block_size, block_start, spi_max_block; 283 | 284 | spi_max_block = get_xfer3_block_size(); 285 | 286 | block_start = 0; 287 | remain = buffer->len; 288 | while (block_start < buffer->len) { 289 | block_size = (remain < spi_max_block) ? remain : spi_max_block; 290 | 291 | Py_BEGIN_ALLOW_THREADS 292 | status = write(self->fd, buffer->buf + block_start, block_size); 293 | Py_END_ALLOW_THREADS 294 | 295 | if (status < 0) { 296 | PyErr_SetFromErrno(PyExc_IOError); 297 | return NULL; 298 | } 299 | 300 | if (status != block_size) { 301 | perror("short write"); 302 | return NULL; 303 | } 304 | 305 | block_start += block_size; 306 | remain -= block_size; 307 | } 308 | 309 | Py_INCREF(Py_None); 310 | return Py_None; 311 | } 312 | 313 | static PyObject * 314 | SpiDev_writebytes2_seq_internal(SpiDevObject *self, PyObject *seq, Py_ssize_t len, uint8_t *buf, Py_ssize_t bufsize) 315 | { 316 | int status; 317 | Py_ssize_t ii, jj, remain, block_size; 318 | char wrmsg_text[4096]; 319 | 320 | remain = len; 321 | jj = 0; 322 | while (remain > 0) { 323 | block_size = (remain < bufsize) ? remain : bufsize; 324 | 325 | for (ii = 0; ii < block_size; ii++, jj++) { 326 | PyObject *val = PySequence_Fast_GET_ITEM(seq, jj); 327 | #if PY_MAJOR_VERSION < 3 328 | if (PyInt_Check(val)) { 329 | buf[ii] = (__u8)PyInt_AS_LONG(val); 330 | } else 331 | #endif 332 | { 333 | if (PyLong_Check(val)) { 334 | buf[ii] = (__u8)PyLong_AS_LONG(val); 335 | } else { 336 | snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val); 337 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 338 | return NULL; 339 | } 340 | } 341 | } 342 | 343 | Py_BEGIN_ALLOW_THREADS 344 | status = write(self->fd, buf, block_size); 345 | Py_END_ALLOW_THREADS 346 | 347 | if (status < 0) { 348 | PyErr_SetFromErrno(PyExc_IOError); 349 | return NULL; 350 | } 351 | 352 | if (status != block_size) { 353 | perror("short write"); 354 | return NULL; 355 | } 356 | 357 | remain -= block_size; 358 | } 359 | 360 | Py_INCREF(Py_None); 361 | return Py_None; 362 | } 363 | 364 | // In writebytes2 we try to avoild doing malloc/free on each tiny block. 365 | // So for any transfer below this size we will use on-stack local buffer instead of allocating one on the heap. 366 | #define SMALL_BUFFER_SIZE 128 367 | 368 | static PyObject * 369 | SpiDev_writebytes2_seq(SpiDevObject *self, PyObject *seq) 370 | { 371 | Py_ssize_t len, bufsize, spi_max_block; 372 | PyObject *result = NULL; 373 | 374 | len = PySequence_Fast_GET_SIZE(seq); 375 | if (len <= 0) { 376 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 377 | return NULL; 378 | } 379 | 380 | spi_max_block = get_xfer3_block_size(); 381 | 382 | bufsize = (len < spi_max_block) ? len : spi_max_block; 383 | 384 | if (bufsize <= SMALL_BUFFER_SIZE) { 385 | // The data size is very small so we can avoid malloc/free completely 386 | // by using a small local buffer instead 387 | uint8_t buf[SMALL_BUFFER_SIZE]; 388 | result = SpiDev_writebytes2_seq_internal(self, seq, len, buf, SMALL_BUFFER_SIZE); 389 | } else { 390 | // Large data, need to allocate buffer on heap 391 | uint8_t *buf; 392 | Py_BEGIN_ALLOW_THREADS 393 | buf = malloc(sizeof(__u8) * bufsize); 394 | Py_END_ALLOW_THREADS 395 | 396 | if (!buf) { 397 | PyErr_SetString(PyExc_OverflowError, wrmsg_oom); 398 | return NULL; 399 | } 400 | 401 | result = SpiDev_writebytes2_seq_internal(self, seq, len, buf, bufsize); 402 | 403 | Py_BEGIN_ALLOW_THREADS 404 | free(buf); 405 | Py_END_ALLOW_THREADS 406 | } 407 | 408 | return result; 409 | } 410 | 411 | PyDoc_STRVAR(SpiDev_writebytes2_doc, 412 | "writebytes2([values]) -> None\n\n" 413 | "Write bytes to SPI device.\n" 414 | "values must be a list or buffer.\n"); 415 | 416 | static PyObject * 417 | SpiDev_writebytes2(SpiDevObject *self, PyObject *args) 418 | { 419 | PyObject *obj, *seq;; 420 | PyObject *result = NULL; 421 | 422 | if (!PyArg_ParseTuple(args, "O:writebytes2", &obj)) { 423 | return NULL; 424 | } 425 | 426 | // Try using buffer protocol if object supports it. 427 | if (PyObject_CheckBuffer(obj) && 1) { 428 | Py_buffer buffer; 429 | if (PyObject_GetBuffer(obj, &buffer, PyBUF_SIMPLE) != -1) { 430 | result = SpiDev_writebytes2_buffer(self, &buffer); 431 | PyBuffer_Release(&buffer); 432 | return result; 433 | } 434 | } 435 | 436 | 437 | // Otherwise, fall back to sequence protocol 438 | seq = PySequence_Fast(obj, "expected a sequence"); 439 | if (seq == NULL) { 440 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 441 | return NULL; 442 | } 443 | 444 | result = SpiDev_writebytes2_seq(self, seq); 445 | 446 | Py_DECREF(seq); 447 | 448 | return result; 449 | 450 | } 451 | 452 | PyDoc_STRVAR(SpiDev_xfer_doc, 453 | "xfer([values]) -> [values]\n\n" 454 | "Perform SPI transaction.\n" 455 | "CS will be released and reactivated between blocks.\n" 456 | "delay specifies delay in usec between blocks.\n"); 457 | 458 | static PyObject * 459 | SpiDev_xfer(SpiDevObject *self, PyObject *args) 460 | { 461 | uint16_t ii, len; 462 | int status; 463 | uint16_t delay_usecs = 0; 464 | uint32_t speed_hz = 0; 465 | uint8_t bits_per_word = 0; 466 | PyObject *obj; 467 | PyObject *seq; 468 | #ifdef SPIDEV_SINGLE 469 | struct spi_ioc_transfer *xferptr; 470 | memset(&xferptr, 0, sizeof(xferptr)); 471 | #else 472 | struct spi_ioc_transfer xfer; 473 | memset(&xfer, 0, sizeof(xfer)); 474 | #endif 475 | uint8_t *txbuf, *rxbuf; 476 | char wrmsg_text[4096]; 477 | 478 | if (!PyArg_ParseTuple(args, "O|IHB:xfer", &obj, &speed_hz, &delay_usecs, &bits_per_word)) 479 | return NULL; 480 | 481 | seq = PySequence_Fast(obj, "expected a sequence"); 482 | if (!seq) { 483 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 484 | return NULL; 485 | } 486 | 487 | len = PySequence_Fast_GET_SIZE(seq); 488 | if (len <= 0) { 489 | Py_DECREF(seq); 490 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 491 | return NULL; 492 | } 493 | 494 | if (len > SPIDEV_MAXPATH) { 495 | snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_listmax, SPIDEV_MAXPATH); 496 | PyErr_SetString(PyExc_OverflowError, wrmsg_text); 497 | Py_DECREF(seq); 498 | return NULL; 499 | } 500 | 501 | txbuf = malloc(sizeof(__u8) * len); 502 | rxbuf = malloc(sizeof(__u8) * len); 503 | 504 | #ifdef SPIDEV_SINGLE 505 | xferptr = (struct spi_ioc_transfer*) malloc(sizeof(struct spi_ioc_transfer) * len); 506 | 507 | for (ii = 0; ii < len; ii++) { 508 | PyObject *val = PySequence_Fast_GET_ITEM(seq, ii); 509 | #if PY_MAJOR_VERSION < 3 510 | if (PyInt_Check(val)) { 511 | txbuf[ii] = (__u8)PyInt_AS_LONG(val); 512 | } else 513 | #endif 514 | { 515 | if (PyLong_Check(val)) { 516 | txbuf[ii] = (__u8)PyLong_AS_LONG(val); 517 | } else { 518 | snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val); 519 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 520 | free(xferptr); 521 | free(txbuf); 522 | free(rxbuf); 523 | Py_DECREF(seq); 524 | return NULL; 525 | } 526 | } 527 | xferptr[ii].tx_buf = (unsigned long)&txbuf[ii]; 528 | xferptr[ii].rx_buf = (unsigned long)&rxbuf[ii]; 529 | xferptr[ii].len = 1; 530 | xferptr[ii].delay_usecs = delay; 531 | xferptr[ii].speed_hz = speed_hz ? speed_hz : self->max_speed_hz; 532 | xferptr[ii].bits_per_word = bits_per_word ? bits_per_word : self->bits_per_word; 533 | #ifdef SPI_IOC_WR_MODE32 534 | xferptr[ii].tx_nbits = 0; 535 | #endif 536 | #ifdef SPI_IOC_RD_MODE32 537 | xferptr[ii].rx_nbits = 0; 538 | #endif 539 | } 540 | 541 | status = ioctl(self->fd, SPI_IOC_MESSAGE(len), xferptr); 542 | free(xferptr); 543 | if (status < 0) { 544 | PyErr_SetFromErrno(PyExc_IOError); 545 | free(txbuf); 546 | free(rxbuf); 547 | Py_DECREF(seq); 548 | return NULL; 549 | } 550 | #else 551 | for (ii = 0; ii < len; ii++) { 552 | PyObject *val = PySequence_Fast_GET_ITEM(seq, ii); 553 | #if PY_MAJOR_VERSION < 3 554 | if (PyInt_Check(val)) { 555 | txbuf[ii] = (__u8)PyInt_AS_LONG(val); 556 | } else 557 | #endif 558 | { 559 | if (PyLong_Check(val)) { 560 | txbuf[ii] = (__u8)PyLong_AS_LONG(val); 561 | } else { 562 | snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_val, val); 563 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 564 | free(txbuf); 565 | free(rxbuf); 566 | Py_DECREF(seq); 567 | return NULL; 568 | } 569 | } 570 | } 571 | 572 | if (PyTuple_Check(obj)) { 573 | Py_DECREF(seq); 574 | seq = PySequence_List(obj); 575 | } 576 | 577 | xfer.tx_buf = (unsigned long)txbuf; 578 | xfer.rx_buf = (unsigned long)rxbuf; 579 | xfer.len = len; 580 | xfer.delay_usecs = delay_usecs; 581 | xfer.speed_hz = speed_hz ? speed_hz : self->max_speed_hz; 582 | xfer.bits_per_word = bits_per_word ? bits_per_word : self->bits_per_word; 583 | #ifdef SPI_IOC_WR_MODE32 584 | xfer.tx_nbits = 0; 585 | #endif 586 | #ifdef SPI_IOC_RD_MODE32 587 | xfer.rx_nbits = 0; 588 | #endif 589 | 590 | status = ioctl(self->fd, SPI_IOC_MESSAGE(1), &xfer); 591 | if (status < 0) { 592 | PyErr_SetFromErrno(PyExc_IOError); 593 | free(txbuf); 594 | free(rxbuf); 595 | Py_DECREF(seq); 596 | return NULL; 597 | } 598 | #endif 599 | 600 | for (ii = 0; ii < len; ii++) { 601 | PyObject *val = PyLong_FromLong((long)rxbuf[ii]); 602 | PySequence_SetItem(seq, ii, val); 603 | Py_DECREF(val); // PySequence_SetItem does not steal reference, must Py_DECREF(val) 604 | } 605 | 606 | // WA: 607 | // in CS_HIGH mode CS isn't pulled to low after transfer, but after read 608 | // reading 0 bytes doesnt matter but brings cs down 609 | // tomdean: 610 | // Stop generating an extra CS except in mode CS_HOGH 611 | if (self->read0 && (self->mode & SPI_CS_HIGH)) status = read(self->fd, &rxbuf[0], 0); 612 | 613 | free(txbuf); 614 | free(rxbuf); 615 | 616 | if (PyTuple_Check(obj)) { 617 | PyObject *old = seq; 618 | seq = PySequence_Tuple(seq); 619 | Py_DECREF(old); 620 | } 621 | 622 | return seq; 623 | } 624 | 625 | 626 | PyDoc_STRVAR(SpiDev_xfer2_doc, 627 | "xfer2([values]) -> [values]\n\n" 628 | "Perform SPI transaction.\n" 629 | "CS will be held active between blocks.\n"); 630 | 631 | static PyObject * 632 | SpiDev_xfer2(SpiDevObject *self, PyObject *args) 633 | { 634 | int status; 635 | uint16_t delay_usecs = 0; 636 | uint32_t speed_hz = 0; 637 | uint8_t bits_per_word = 0; 638 | uint16_t ii, len; 639 | PyObject *obj; 640 | PyObject *seq; 641 | struct spi_ioc_transfer xfer; 642 | Py_BEGIN_ALLOW_THREADS 643 | memset(&xfer, 0, sizeof(xfer)); 644 | Py_END_ALLOW_THREADS 645 | uint8_t *txbuf, *rxbuf; 646 | char wrmsg_text[4096]; 647 | 648 | if (!PyArg_ParseTuple(args, "O|IHB:xfer2", &obj, &speed_hz, &delay_usecs, &bits_per_word)) 649 | return NULL; 650 | 651 | seq = PySequence_Fast(obj, "expected a sequence"); 652 | if (!seq) { 653 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 654 | return NULL; 655 | } 656 | 657 | len = PySequence_Fast_GET_SIZE(seq); 658 | if (len <= 0) { 659 | Py_DECREF(seq); 660 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 661 | return NULL; 662 | } 663 | 664 | if (len > SPIDEV_MAXPATH) { 665 | snprintf(wrmsg_text, sizeof(wrmsg_text) - 1, wrmsg_listmax, SPIDEV_MAXPATH); 666 | PyErr_SetString(PyExc_OverflowError, wrmsg_text); 667 | Py_DECREF(seq); 668 | return NULL; 669 | } 670 | 671 | Py_BEGIN_ALLOW_THREADS 672 | txbuf = malloc(sizeof(__u8) * len); 673 | rxbuf = malloc(sizeof(__u8) * len); 674 | Py_END_ALLOW_THREADS 675 | 676 | for (ii = 0; ii < len; ii++) { 677 | PyObject *val = PySequence_Fast_GET_ITEM(seq, ii); 678 | #if PY_MAJOR_VERSION < 3 679 | if (PyInt_Check(val)) { 680 | txbuf[ii] = (__u8)PyInt_AS_LONG(val); 681 | } else 682 | #endif 683 | { 684 | if (PyLong_Check(val)) { 685 | txbuf[ii] = (__u8)PyLong_AS_LONG(val); 686 | } else { 687 | snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val); 688 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 689 | free(txbuf); 690 | free(rxbuf); 691 | Py_DECREF(seq); 692 | return NULL; 693 | } 694 | } 695 | } 696 | 697 | if (PyTuple_Check(obj)) { 698 | Py_DECREF(seq); 699 | seq = PySequence_List(obj); 700 | } 701 | 702 | Py_BEGIN_ALLOW_THREADS 703 | xfer.tx_buf = (unsigned long)txbuf; 704 | xfer.rx_buf = (unsigned long)rxbuf; 705 | xfer.len = len; 706 | xfer.delay_usecs = delay_usecs; 707 | xfer.speed_hz = speed_hz ? speed_hz : self->max_speed_hz; 708 | xfer.bits_per_word = bits_per_word ? bits_per_word : self->bits_per_word; 709 | 710 | status = ioctl(self->fd, SPI_IOC_MESSAGE(1), &xfer); 711 | Py_END_ALLOW_THREADS 712 | if (status < 0) { 713 | PyErr_SetFromErrno(PyExc_IOError); 714 | free(txbuf); 715 | free(rxbuf); 716 | Py_DECREF(seq); 717 | return NULL; 718 | } 719 | 720 | for (ii = 0; ii < len; ii++) { 721 | PyObject *val = PyLong_FromLong((long)rxbuf[ii]); 722 | PySequence_SetItem(seq, ii, val); 723 | Py_DECREF(val); // PySequence_SetItem does not steal reference, must Py_DECREF(val) 724 | } 725 | // WA: 726 | // in CS_HIGH mode CS isnt pulled to low after transfer 727 | // reading 0 bytes doesn't really matter but brings CS down 728 | // tomdean: 729 | // Stop generating an extra CS except in mode CS_HOGH 730 | if (self->read0 && (self->mode & SPI_CS_HIGH)) status = read(self->fd, &rxbuf[0], 0); 731 | 732 | Py_BEGIN_ALLOW_THREADS 733 | free(txbuf); 734 | free(rxbuf); 735 | Py_END_ALLOW_THREADS 736 | 737 | 738 | if (PyTuple_Check(obj)) { 739 | PyObject *old = seq; 740 | seq = PySequence_Tuple(seq); 741 | Py_DECREF(old); 742 | } 743 | 744 | return seq; 745 | } 746 | 747 | PyDoc_STRVAR(SpiDev_xfer3_doc, 748 | "xfer3([values]) -> [values]\n\n" 749 | "Perform SPI transaction. Accepts input of arbitrary size.\n" 750 | "Large blocks will be send as multiple transactions\n" 751 | "CS will be held active between blocks.\n"); 752 | 753 | static PyObject * 754 | SpiDev_xfer3(SpiDevObject *self, PyObject *args) 755 | { 756 | int status; 757 | uint16_t delay_usecs = 0; 758 | uint32_t speed_hz = 0; 759 | uint8_t bits_per_word = 0; 760 | Py_ssize_t ii, jj, len, block_size, block_start, bufsize; 761 | PyObject *obj; 762 | PyObject *seq; 763 | PyObject *rx_tuple; 764 | struct spi_ioc_transfer xfer; 765 | Py_BEGIN_ALLOW_THREADS 766 | memset(&xfer, 0, sizeof(xfer)); 767 | Py_END_ALLOW_THREADS 768 | uint8_t *txbuf, *rxbuf; 769 | char wrmsg_text[4096]; 770 | 771 | if (!PyArg_ParseTuple(args, "O|IHB:xfer3", &obj, &speed_hz, &delay_usecs, &bits_per_word)) 772 | return NULL; 773 | 774 | seq = PySequence_Fast(obj, "expected a sequence"); 775 | if (!seq) { 776 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 777 | return NULL; 778 | } 779 | 780 | len = PySequence_Fast_GET_SIZE(seq); 781 | if (len <= 0) { 782 | Py_DECREF(seq); 783 | PyErr_SetString(PyExc_TypeError, wrmsg_list0); 784 | return NULL; 785 | } 786 | 787 | bufsize = get_xfer3_block_size(); 788 | if (bufsize > len) { 789 | bufsize = len; 790 | } 791 | 792 | rx_tuple = PyTuple_New(len); 793 | if (!rx_tuple) { 794 | Py_DECREF(seq); 795 | PyErr_SetString(PyExc_OverflowError, wrmsg_oom); 796 | return NULL; 797 | } 798 | 799 | Py_BEGIN_ALLOW_THREADS 800 | // Allocate tx and rx buffers immediately releasing them if any allocation fails 801 | if ((txbuf = malloc(sizeof(__u8) * bufsize)) != NULL) { 802 | if ((rxbuf = malloc(sizeof(__u8) * bufsize)) != NULL) { 803 | // All good, both buffers allocated 804 | } else { 805 | // rxbuf allocation failed while txbuf succeeded 806 | free(txbuf); 807 | txbuf = NULL; 808 | } 809 | } else { 810 | // txbuf allocation failed 811 | rxbuf = NULL; 812 | } 813 | Py_END_ALLOW_THREADS 814 | if (!txbuf || !rxbuf) { 815 | // Allocation failed. Buffers has been freed already 816 | Py_DECREF(seq); 817 | Py_DECREF(rx_tuple); 818 | PyErr_SetString(PyExc_OverflowError, wrmsg_oom); 819 | return NULL; 820 | } 821 | 822 | 823 | block_start = 0; 824 | while (block_start < len) { 825 | 826 | for (ii = 0, jj = block_start; jj < len && ii < bufsize; ii++, jj++) { 827 | PyObject *val = PySequence_Fast_GET_ITEM(seq, jj); 828 | #if PY_MAJOR_VERSION < 3 829 | if (PyInt_Check(val)) { 830 | txbuf[ii] = (__u8)PyInt_AS_LONG(val); 831 | } else 832 | #endif 833 | { 834 | if (PyLong_Check(val)) { 835 | txbuf[ii] = (__u8)PyLong_AS_LONG(val); 836 | } else { 837 | snprintf(wrmsg_text, sizeof (wrmsg_text) - 1, wrmsg_val, val); 838 | PyErr_SetString(PyExc_TypeError, wrmsg_text); 839 | free(txbuf); 840 | free(rxbuf); 841 | Py_DECREF(rx_tuple); 842 | Py_DECREF(seq); 843 | return NULL; 844 | } 845 | } 846 | } 847 | 848 | block_size = ii; 849 | 850 | Py_BEGIN_ALLOW_THREADS 851 | xfer.tx_buf = (unsigned long)txbuf; 852 | xfer.rx_buf = (unsigned long)rxbuf; 853 | xfer.len = block_size; 854 | xfer.delay_usecs = delay_usecs; 855 | xfer.speed_hz = speed_hz ? speed_hz : self->max_speed_hz; 856 | xfer.bits_per_word = bits_per_word ? bits_per_word : self->bits_per_word; 857 | 858 | status = ioctl(self->fd, SPI_IOC_MESSAGE(1), &xfer); 859 | Py_END_ALLOW_THREADS 860 | 861 | if (status < 0) { 862 | PyErr_SetFromErrno(PyExc_IOError); 863 | free(txbuf); 864 | free(rxbuf); 865 | Py_DECREF(rx_tuple); 866 | Py_DECREF(seq); 867 | return NULL; 868 | } 869 | for (ii = 0, jj = block_start; ii < block_size; ii++, jj++) { 870 | PyObject *val = PyLong_FromLong((long)rxbuf[ii]); 871 | PyTuple_SetItem(rx_tuple, jj, val); // Steals reference, no need to Py_DECREF(val) 872 | } 873 | 874 | block_start += block_size; 875 | } 876 | 877 | 878 | // WA: 879 | // in CS_HIGH mode CS isnt pulled to low after transfer 880 | // reading 0 bytes doesn't really matter but brings CS down 881 | // tomdean: 882 | // Stop generating an extra CS except in mode CS_HIGH 883 | if (self->read0 && (self->mode & SPI_CS_HIGH)) status = read(self->fd, &rxbuf[0], 0); 884 | 885 | Py_BEGIN_ALLOW_THREADS 886 | free(txbuf); 887 | free(rxbuf); 888 | Py_END_ALLOW_THREADS 889 | 890 | Py_DECREF(seq); 891 | 892 | return rx_tuple; 893 | } 894 | 895 | static int __spidev_set_mode( int fd, __u8 mode) { 896 | __u8 test; 897 | if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) { 898 | PyErr_SetFromErrno(PyExc_IOError); 899 | return -1; 900 | } 901 | if (ioctl(fd, SPI_IOC_RD_MODE, &test) == -1) { 902 | PyErr_SetFromErrno(PyExc_IOError); 903 | return -1; 904 | } 905 | if (test != mode) { 906 | PyErr_Format(PyExc_IOError, 907 | "Attempted to set mode 0x%x but mode 0x%x returned", 908 | (unsigned int)mode, (unsigned int)test); 909 | return -1; 910 | } 911 | return 0; 912 | } 913 | 914 | PyDoc_STRVAR(SpiDev_fileno_doc, 915 | "fileno() -> integer \"file descriptor\"\n\n" 916 | "This is needed for lower-level file interfaces, such as os.read().\n"); 917 | 918 | static PyObject * 919 | SpiDev_fileno(SpiDevObject *self) 920 | { 921 | PyObject *result = Py_BuildValue("i", self->fd); 922 | Py_INCREF(result); 923 | return result; 924 | } 925 | 926 | static PyObject * 927 | SpiDev_get_mode(SpiDevObject *self, void *closure) 928 | { 929 | PyObject *result = Py_BuildValue("i", (self->mode & (SPI_CPHA | SPI_CPOL) ) ); 930 | Py_INCREF(result); 931 | return result; 932 | } 933 | 934 | static PyObject * 935 | SpiDev_get_cshigh(SpiDevObject *self, void *closure) 936 | { 937 | PyObject *result; 938 | 939 | if (self->mode & SPI_CS_HIGH) 940 | result = Py_True; 941 | else 942 | result = Py_False; 943 | 944 | Py_INCREF(result); 945 | return result; 946 | } 947 | 948 | static PyObject * 949 | SpiDev_get_lsbfirst(SpiDevObject *self, void *closure) 950 | { 951 | PyObject *result; 952 | 953 | if (self->mode & SPI_LSB_FIRST) 954 | result = Py_True; 955 | else 956 | result = Py_False; 957 | 958 | Py_INCREF(result); 959 | return result; 960 | } 961 | 962 | static PyObject * 963 | SpiDev_get_3wire(SpiDevObject *self, void *closure) 964 | { 965 | PyObject *result; 966 | 967 | if (self->mode & SPI_3WIRE) 968 | result = Py_True; 969 | else 970 | result = Py_False; 971 | 972 | Py_INCREF(result); 973 | return result; 974 | } 975 | 976 | static PyObject * 977 | SpiDev_get_loop(SpiDevObject *self, void *closure) 978 | { 979 | PyObject *result; 980 | 981 | if (self->mode & SPI_LOOP) 982 | result = Py_True; 983 | else 984 | result = Py_False; 985 | 986 | Py_INCREF(result); 987 | return result; 988 | } 989 | 990 | static PyObject * 991 | SpiDev_get_no_cs(SpiDevObject *self, void *closure) 992 | { 993 | PyObject *result; 994 | 995 | if (self->mode & SPI_NO_CS) 996 | result = Py_True; 997 | else 998 | result = Py_False; 999 | 1000 | Py_INCREF(result); 1001 | return result; 1002 | } 1003 | 1004 | 1005 | static int 1006 | SpiDev_set_mode(SpiDevObject *self, PyObject *val, void *closure) 1007 | { 1008 | uint8_t mode, tmp; 1009 | int ret; 1010 | 1011 | if (val == NULL) { 1012 | PyErr_SetString(PyExc_TypeError, 1013 | "Cannot delete attribute"); 1014 | return -1; 1015 | } 1016 | #if PY_MAJOR_VERSION < 3 1017 | if (PyInt_Check(val)) { 1018 | mode = PyInt_AS_LONG(val); 1019 | } else 1020 | #endif 1021 | { 1022 | if (PyLong_Check(val)) { 1023 | mode = PyLong_AS_LONG(val); 1024 | } else { 1025 | PyErr_SetString(PyExc_TypeError, 1026 | "The mode attribute must be an integer"); 1027 | return -1; 1028 | } 1029 | } 1030 | 1031 | 1032 | if ( mode > 3 ) { 1033 | PyErr_SetString(PyExc_TypeError, 1034 | "The mode attribute must be an integer" 1035 | "between 0 and 3."); 1036 | return -1; 1037 | } 1038 | 1039 | // clean and set CPHA and CPOL bits 1040 | tmp = ( self->mode & ~(SPI_CPHA | SPI_CPOL) ) | mode ; 1041 | 1042 | ret = __spidev_set_mode(self->fd, tmp); 1043 | 1044 | if (ret != -1) 1045 | self->mode = tmp; 1046 | return ret; 1047 | } 1048 | 1049 | static int 1050 | SpiDev_set_cshigh(SpiDevObject *self, PyObject *val, void *closure) 1051 | { 1052 | uint8_t tmp; 1053 | int ret; 1054 | 1055 | if (val == NULL) { 1056 | PyErr_SetString(PyExc_TypeError, 1057 | "Cannot delete attribute"); 1058 | return -1; 1059 | } 1060 | else if (!PyBool_Check(val)) { 1061 | PyErr_SetString(PyExc_TypeError, 1062 | "The cshigh attribute must be boolean"); 1063 | return -1; 1064 | } 1065 | 1066 | if (val == Py_True) 1067 | tmp = self->mode | SPI_CS_HIGH; 1068 | else 1069 | tmp = self->mode & ~SPI_CS_HIGH; 1070 | 1071 | ret = __spidev_set_mode(self->fd, tmp); 1072 | 1073 | if (ret != -1) 1074 | self->mode = tmp; 1075 | return ret; 1076 | } 1077 | 1078 | static int 1079 | SpiDev_set_lsbfirst(SpiDevObject *self, PyObject *val, void *closure) 1080 | { 1081 | uint8_t tmp; 1082 | int ret; 1083 | 1084 | if (val == NULL) { 1085 | PyErr_SetString(PyExc_TypeError, 1086 | "Cannot delete attribute"); 1087 | return -1; 1088 | } 1089 | else if (!PyBool_Check(val)) { 1090 | PyErr_SetString(PyExc_TypeError, 1091 | "The lsbfirst attribute must be boolean"); 1092 | return -1; 1093 | } 1094 | 1095 | if (val == Py_True) 1096 | tmp = self->mode | SPI_LSB_FIRST; 1097 | else 1098 | tmp = self->mode & ~SPI_LSB_FIRST; 1099 | 1100 | ret = __spidev_set_mode(self->fd, tmp); 1101 | 1102 | if (ret != -1) 1103 | self->mode = tmp; 1104 | return ret; 1105 | } 1106 | 1107 | static int 1108 | SpiDev_set_3wire(SpiDevObject *self, PyObject *val, void *closure) 1109 | { 1110 | uint8_t tmp; 1111 | int ret; 1112 | 1113 | if (val == NULL) { 1114 | PyErr_SetString(PyExc_TypeError, 1115 | "Cannot delete attribute"); 1116 | return -1; 1117 | } 1118 | else if (!PyBool_Check(val)) { 1119 | PyErr_SetString(PyExc_TypeError, 1120 | "The 3wire attribute must be boolean"); 1121 | return -1; 1122 | } 1123 | 1124 | if (val == Py_True) 1125 | tmp = self->mode | SPI_3WIRE; 1126 | else 1127 | tmp = self->mode & ~SPI_3WIRE; 1128 | 1129 | ret = __spidev_set_mode(self->fd, tmp); 1130 | 1131 | if (ret != -1) 1132 | self->mode = tmp; 1133 | return ret; 1134 | } 1135 | 1136 | static int 1137 | SpiDev_set_no_cs(SpiDevObject *self, PyObject *val, void *closure) 1138 | { 1139 | uint8_t tmp; 1140 | int ret; 1141 | 1142 | if (val == NULL) { 1143 | PyErr_SetString(PyExc_TypeError, 1144 | "Cannot delete attribute"); 1145 | return -1; 1146 | } 1147 | else if (!PyBool_Check(val)) { 1148 | PyErr_SetString(PyExc_TypeError, 1149 | "The no_cs attribute must be boolean"); 1150 | return -1; 1151 | } 1152 | 1153 | if (val == Py_True) 1154 | tmp = self->mode | SPI_NO_CS; 1155 | else 1156 | tmp = self->mode & ~SPI_NO_CS; 1157 | 1158 | ret = __spidev_set_mode(self->fd, tmp); 1159 | 1160 | if (ret != -1) 1161 | self->mode = tmp; 1162 | return ret; 1163 | } 1164 | 1165 | 1166 | static int 1167 | SpiDev_set_loop(SpiDevObject *self, PyObject *val, void *closure) 1168 | { 1169 | uint8_t tmp; 1170 | int ret; 1171 | 1172 | if (val == NULL) { 1173 | PyErr_SetString(PyExc_TypeError, 1174 | "Cannot delete attribute"); 1175 | return -1; 1176 | } 1177 | else if (!PyBool_Check(val)) { 1178 | PyErr_SetString(PyExc_TypeError, 1179 | "The loop attribute must be boolean"); 1180 | return -1; 1181 | } 1182 | 1183 | if (val == Py_True) 1184 | tmp = self->mode | SPI_LOOP; 1185 | else 1186 | tmp = self->mode & ~SPI_LOOP; 1187 | 1188 | ret = __spidev_set_mode(self->fd, tmp); 1189 | 1190 | if (ret != -1) 1191 | self->mode = tmp; 1192 | return ret; 1193 | } 1194 | 1195 | static PyObject * 1196 | SpiDev_get_bits_per_word(SpiDevObject *self, void *closure) 1197 | { 1198 | PyObject *result = Py_BuildValue("i", self->bits_per_word); 1199 | Py_INCREF(result); 1200 | return result; 1201 | } 1202 | 1203 | static int 1204 | SpiDev_set_bits_per_word(SpiDevObject *self, PyObject *val, void *closure) 1205 | { 1206 | uint8_t bits; 1207 | 1208 | if (val == NULL) { 1209 | PyErr_SetString(PyExc_TypeError, 1210 | "Cannot delete attribute"); 1211 | return -1; 1212 | } 1213 | #if PY_MAJOR_VERSION < 3 1214 | if (PyInt_Check(val)) { 1215 | bits = PyInt_AS_LONG(val); 1216 | } else 1217 | #endif 1218 | { 1219 | if (PyLong_Check(val)) { 1220 | bits = PyLong_AS_LONG(val); 1221 | } else { 1222 | PyErr_SetString(PyExc_TypeError, 1223 | "The bits_per_word attribute must be an integer"); 1224 | return -1; 1225 | } 1226 | } 1227 | 1228 | if (bits < 8 || bits > 32) { 1229 | PyErr_SetString(PyExc_TypeError, 1230 | "invalid bits_per_word (8 to 32)"); 1231 | return -1; 1232 | } 1233 | 1234 | if (self->bits_per_word != bits) { 1235 | if (ioctl(self->fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) { 1236 | PyErr_SetFromErrno(PyExc_IOError); 1237 | return -1; 1238 | } 1239 | self->bits_per_word = bits; 1240 | } 1241 | return 0; 1242 | } 1243 | 1244 | static PyObject * 1245 | SpiDev_get_max_speed_hz(SpiDevObject *self, void *closure) 1246 | { 1247 | PyObject *result = Py_BuildValue("i", self->max_speed_hz); 1248 | Py_INCREF(result); 1249 | return result; 1250 | } 1251 | 1252 | static int 1253 | SpiDev_set_max_speed_hz(SpiDevObject *self, PyObject *val, void *closure) 1254 | { 1255 | uint32_t max_speed_hz; 1256 | 1257 | if (val == NULL) { 1258 | PyErr_SetString(PyExc_TypeError, 1259 | "Cannot delete attribute"); 1260 | return -1; 1261 | } 1262 | #if PY_MAJOR_VERSION < 3 1263 | if (PyInt_Check(val)) { 1264 | max_speed_hz = PyInt_AS_LONG(val); 1265 | } else 1266 | #endif 1267 | { 1268 | if (PyLong_Check(val)) { 1269 | max_speed_hz = PyLong_AS_LONG(val); 1270 | } else { 1271 | PyErr_SetString(PyExc_TypeError, 1272 | "The max_speed_hz attribute must be an integer"); 1273 | return -1; 1274 | } 1275 | } 1276 | 1277 | if (self->max_speed_hz != max_speed_hz) { 1278 | if (ioctl(self->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz) == -1) { 1279 | PyErr_SetFromErrno(PyExc_IOError); 1280 | return -1; 1281 | } 1282 | self->max_speed_hz = max_speed_hz; 1283 | } 1284 | return 0; 1285 | } 1286 | 1287 | static PyObject * 1288 | SpiDev_get_read0(SpiDevObject *self, void *closure) 1289 | { 1290 | PyObject *result = (self->read0 == 1) ? Py_True : Py_False; 1291 | Py_INCREF(result); 1292 | return result; 1293 | } 1294 | 1295 | static int 1296 | SpiDev_set_read0(SpiDevObject *self, PyObject *val, void *closure) 1297 | { 1298 | if (val == NULL) { 1299 | PyErr_SetString(PyExc_TypeError, 1300 | "Cannot delete attribute"); 1301 | return -1; 1302 | } 1303 | else if (!PyBool_Check(val)) { 1304 | PyErr_SetString(PyExc_TypeError, 1305 | "The read0 attribute must be boolean"); 1306 | return -1; 1307 | } 1308 | 1309 | self->read0 = (val == Py_True) ? 1 : 0; 1310 | 1311 | return 0; 1312 | } 1313 | 1314 | static PyGetSetDef SpiDev_getset[] = { 1315 | {"mode", (getter)SpiDev_get_mode, (setter)SpiDev_set_mode, 1316 | "SPI mode as two bit pattern of \n" 1317 | "Clock Polarity and Phase [CPOL|CPHA]\n" 1318 | "min: 0b00 = 0 max: 0b11 = 3\n"}, 1319 | {"cshigh", (getter)SpiDev_get_cshigh, (setter)SpiDev_set_cshigh, 1320 | "CS active high\n"}, 1321 | {"threewire", (getter)SpiDev_get_3wire, (setter)SpiDev_set_3wire, 1322 | "SI/SO signals shared\n"}, 1323 | {"lsbfirst", (getter)SpiDev_get_lsbfirst, (setter)SpiDev_set_lsbfirst, 1324 | "LSB first\n"}, 1325 | {"loop", (getter)SpiDev_get_loop, (setter)SpiDev_set_loop, 1326 | "loopback configuration\n"}, 1327 | {"no_cs", (getter)SpiDev_get_no_cs, (setter)SpiDev_set_no_cs, 1328 | "disable chip select\n"}, 1329 | {"bits_per_word", (getter)SpiDev_get_bits_per_word, (setter)SpiDev_set_bits_per_word, 1330 | "bits per word\n"}, 1331 | {"max_speed_hz", (getter)SpiDev_get_max_speed_hz, (setter)SpiDev_set_max_speed_hz, 1332 | "maximum speed in Hz\n"}, 1333 | {"read0", (getter)SpiDev_get_read0, (setter)SpiDev_set_read0, 1334 | "Read 0 bytes after transfer to lower CS if cshigh == True\n"}, 1335 | {NULL}, 1336 | }; 1337 | 1338 | PyDoc_STRVAR(SpiDev_open_doc, 1339 | "open(bus, device)\n\n" 1340 | "Connects the object to the specified SPI device.\n" 1341 | "open(X,Y) will open /dev/spidev.\n"); 1342 | 1343 | static PyObject * 1344 | SpiDev_open(SpiDevObject *self, PyObject *args, PyObject *kwds) 1345 | { 1346 | int bus, device; 1347 | char path[SPIDEV_MAXPATH]; 1348 | uint8_t tmp8; 1349 | uint32_t tmp32; 1350 | static char *kwlist[] = {"bus", "device", NULL}; 1351 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii:open", kwlist, &bus, &device)) 1352 | return NULL; 1353 | if (snprintf(path, SPIDEV_MAXPATH, "/dev/spidev%d.%d", bus, device) >= SPIDEV_MAXPATH) { 1354 | PyErr_SetString(PyExc_OverflowError, 1355 | "Bus and/or device number is invalid."); 1356 | return NULL; 1357 | } 1358 | if ((self->fd = open(path, O_RDWR, 0)) == -1) { 1359 | PyErr_SetFromErrno(PyExc_IOError); 1360 | return NULL; 1361 | } 1362 | if (ioctl(self->fd, SPI_IOC_RD_MODE, &tmp8) == -1) { 1363 | PyErr_SetFromErrno(PyExc_IOError); 1364 | return NULL; 1365 | } 1366 | self->mode = tmp8; 1367 | if (ioctl(self->fd, SPI_IOC_RD_BITS_PER_WORD, &tmp8) == -1) { 1368 | PyErr_SetFromErrno(PyExc_IOError); 1369 | return NULL; 1370 | } 1371 | self->bits_per_word = tmp8; 1372 | if (ioctl(self->fd, SPI_IOC_RD_MAX_SPEED_HZ, &tmp32) == -1) { 1373 | PyErr_SetFromErrno(PyExc_IOError); 1374 | return NULL; 1375 | } 1376 | self->max_speed_hz = tmp32; 1377 | 1378 | Py_INCREF(Py_None); 1379 | return Py_None; 1380 | } 1381 | 1382 | static int 1383 | SpiDev_init(SpiDevObject *self, PyObject *args, PyObject *kwds) 1384 | { 1385 | int bus = -1; 1386 | int client = -1; 1387 | static char *kwlist[] = {"bus", "client", NULL}; 1388 | 1389 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:__init__", 1390 | kwlist, &bus, &client)) 1391 | return -1; 1392 | 1393 | if (bus >= 0) { 1394 | SpiDev_open(self, args, kwds); 1395 | if (PyErr_Occurred()) 1396 | return -1; 1397 | } 1398 | 1399 | return 0; 1400 | } 1401 | 1402 | 1403 | PyDoc_STRVAR(SpiDevObjectType_doc, 1404 | "SpiDev([bus],[client]) -> SPI\n\n" 1405 | "Return a new SPI object that is (optionally) connected to the\n" 1406 | "specified SPI device interface.\n"); 1407 | 1408 | static 1409 | PyObject *SpiDev_enter(PyObject *self, PyObject *args) 1410 | { 1411 | if (!PyArg_ParseTuple(args, "")) 1412 | return NULL; 1413 | 1414 | Py_INCREF(self); 1415 | return self; 1416 | } 1417 | 1418 | static 1419 | PyObject *SpiDev_exit(SpiDevObject *self, PyObject *args) 1420 | { 1421 | 1422 | PyObject *exc_type = 0; 1423 | PyObject *exc_value = 0; 1424 | PyObject *traceback = 0; 1425 | if (!PyArg_UnpackTuple(args, "__exit__", 3, 3, &exc_type, &exc_value, 1426 | &traceback)) { 1427 | return 0; 1428 | } 1429 | 1430 | SpiDev_close(self); 1431 | Py_RETURN_FALSE; 1432 | } 1433 | 1434 | static PyMethodDef SpiDev_methods[] = { 1435 | {"open", (PyCFunction)SpiDev_open, METH_VARARGS | METH_KEYWORDS, 1436 | SpiDev_open_doc}, 1437 | {"close", (PyCFunction)SpiDev_close, METH_NOARGS, 1438 | SpiDev_close_doc}, 1439 | {"fileno", (PyCFunction)SpiDev_fileno, METH_NOARGS, 1440 | SpiDev_fileno_doc}, 1441 | {"readbytes", (PyCFunction)SpiDev_readbytes, METH_VARARGS, 1442 | SpiDev_read_doc}, 1443 | {"writebytes", (PyCFunction)SpiDev_writebytes, METH_VARARGS, 1444 | SpiDev_write_doc}, 1445 | {"writebytes2", (PyCFunction)SpiDev_writebytes2, METH_VARARGS, 1446 | SpiDev_writebytes2_doc}, 1447 | {"xfer", (PyCFunction)SpiDev_xfer, METH_VARARGS, 1448 | SpiDev_xfer_doc}, 1449 | {"xfer2", (PyCFunction)SpiDev_xfer2, METH_VARARGS, 1450 | SpiDev_xfer2_doc}, 1451 | {"xfer3", (PyCFunction)SpiDev_xfer3, METH_VARARGS, 1452 | SpiDev_xfer3_doc}, 1453 | {"__enter__", (PyCFunction)SpiDev_enter, METH_VARARGS, 1454 | NULL}, 1455 | {"__exit__", (PyCFunction)SpiDev_exit, METH_VARARGS, 1456 | NULL}, 1457 | {NULL}, 1458 | }; 1459 | 1460 | static PyTypeObject SpiDevObjectType = { 1461 | #if PY_MAJOR_VERSION >= 3 1462 | PyVarObject_HEAD_INIT(NULL, 0) 1463 | #else 1464 | PyObject_HEAD_INIT(NULL) 1465 | 0, /* ob_size */ 1466 | #endif 1467 | "SpiDev", /* tp_name */ 1468 | sizeof(SpiDevObject), /* tp_basicsize */ 1469 | 0, /* tp_itemsize */ 1470 | (destructor)SpiDev_dealloc, /* tp_dealloc */ 1471 | 0, /* tp_print */ 1472 | 0, /* tp_getattr */ 1473 | 0, /* tp_setattr */ 1474 | 0, /* tp_compare */ 1475 | 0, /* tp_repr */ 1476 | 0, /* tp_as_number */ 1477 | 0, /* tp_as_sequence */ 1478 | 0, /* tp_as_mapping */ 1479 | 0, /* tp_hash */ 1480 | 0, /* tp_call */ 1481 | 0, /* tp_str */ 1482 | 0, /* tp_getattro */ 1483 | 0, /* tp_setattro */ 1484 | 0, /* tp_as_buffer */ 1485 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ 1486 | SpiDevObjectType_doc, /* tp_doc */ 1487 | 0, /* tp_traverse */ 1488 | 0, /* tp_clear */ 1489 | 0, /* tp_richcompare */ 1490 | 0, /* tp_weaklistoffset */ 1491 | 0, /* tp_iter */ 1492 | 0, /* tp_iternext */ 1493 | SpiDev_methods, /* tp_methods */ 1494 | 0, /* tp_members */ 1495 | SpiDev_getset, /* tp_getset */ 1496 | 0, /* tp_base */ 1497 | 0, /* tp_dict */ 1498 | 0, /* tp_descr_get */ 1499 | 0, /* tp_descr_set */ 1500 | 0, /* tp_dictoffset */ 1501 | (initproc)SpiDev_init, /* tp_init */ 1502 | 0, /* tp_alloc */ 1503 | SpiDev_new, /* tp_new */ 1504 | }; 1505 | 1506 | static PyMethodDef SpiDev_module_methods[] = { 1507 | {NULL} 1508 | }; 1509 | 1510 | #if PY_MAJOR_VERSION >= 3 1511 | static struct PyModuleDef moduledef = { 1512 | PyModuleDef_HEAD_INIT, 1513 | "spidev", 1514 | SpiDev_module_doc, 1515 | -1, 1516 | SpiDev_module_methods, 1517 | NULL, 1518 | NULL, 1519 | NULL, 1520 | NULL, 1521 | }; 1522 | #else 1523 | #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ 1524 | #define PyMODINIT_FUNC void 1525 | #endif 1526 | #endif 1527 | 1528 | #if PY_MAJOR_VERSION >= 3 1529 | PyMODINIT_FUNC 1530 | PyInit_spidev(void) 1531 | #else 1532 | void initspidev(void) 1533 | #endif 1534 | { 1535 | PyObject* m; 1536 | 1537 | if (PyType_Ready(&SpiDevObjectType) < 0) 1538 | #if PY_MAJOR_VERSION >= 3 1539 | return NULL; 1540 | #else 1541 | return; 1542 | #endif 1543 | 1544 | #if PY_MAJOR_VERSION >= 3 1545 | m = PyModule_Create(&moduledef); 1546 | PyObject *version = PyUnicode_FromString(_VERSION_); 1547 | #else 1548 | m = Py_InitModule3("spidev", SpiDev_module_methods, SpiDev_module_doc); 1549 | PyObject *version = PyString_FromString(_VERSION_); 1550 | #endif 1551 | 1552 | PyObject *dict = PyModule_GetDict(m); 1553 | PyDict_SetItemString(dict, "__version__", version); 1554 | Py_DECREF(version); 1555 | 1556 | Py_INCREF(&SpiDevObjectType); 1557 | PyModule_AddObject(m, "SpiDev", (PyObject *)&SpiDevObjectType); 1558 | 1559 | #if PY_MAJOR_VERSION >= 3 1560 | return m; 1561 | #endif 1562 | } 1563 | --------------------------------------------------------------------------------