Download the PHP package microscrap/spi without Composer
On this page you can find all versions of the php package microscrap/spi. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download microscrap/spi
More information about microscrap/spi
Files in microscrap/spi
Package spi
Short Description Unix spidev Bindings for The PHP Posi Extension
License MIT
Homepage https://dosr.projectsaturnstudios.com
Informations about the package spi
microscrap/spi — Linux SPI / spidev bindings for ScrapyardIO
PHP library that wraps the posi extension with global helpers, enums, and data objects. Every helper delegates to a facade class under Microscrap\Bindings\SPI.
This project provides PHP bindings to the Linux spidev character device API, mirroring the public surface of <linux/spi/spidev.h> (the SPI_IOC_* ioctl family used by spi-tools, Python's spidev, and friends).
Highlights
- Open a spidev device (
/dev/spidev0.0,/dev/spidev1.1, etc.) and configure mode, clock speed, and word size in one call - Half-duplex byte I/O via
spi_read/spi_write(usesposix_read/posix_writeunder the hood) - Full-duplex, chained transfers via
spi_transferand theSPITransferdata object — packsspi_ioc_transferand issuesSPI_IOC_MESSAGE(n) - Per-segment overrides: clock speed, bits-per-word, inter-word delay, CS-change, dual/quad lane counts
- Inspect and mutate every spidev attribute —
mode,max_speed_hz,bits_per_word,lsb_first - Typed
SPIModebitmask covers CPOL/CPHA, CS polarity, 3-wire, loopback, no-CS, dual/quad/octal lanes, ready signal - Automatically prefers a native
spi_transfer(int $fd, …)from a low-level extension when one is loaded, otherwise falls back to theext-posimemory path - Thin global
spi_*helper API — all functions arefunction_exists-guarded
Requirements
- PHP 8.3+
- Linux kernel with
spidevenabled and a populated/dev/spidev*device - ext-posi ^0.4.0 — install from php-io-extensions/posi; the
posi_mem_*helpers are required forspi_transferunless a nativespi_transfer(int $fd, …)is loaded - microscrap/posix ^0.4.0
Installation
Confirm ext-posi is loaded:
Confirm the spidev device is visible (and that your user can access it, or run as root):
On a Raspberry Pi, enable SPI via raspi-config or by adding dtparam=spi=on to /boot/config.txt.
Composer autoloads src/Helpers/spi-device.php, registering the global spi_* functions.
Usage
SPI transactions are driven through global helper functions (spi_open, spi_read, spi_write, spi_transfer, etc.). All helpers delegate to the Device facade and are only defined once (function_exists guard).
Enums live under Microscrap\Bindings\SPI\Enums. The device handle is Microscrap\Bindings\SPI\DataObjects\SPIDevice, and a single transfer segment is described by Microscrap\Bindings\SPI\DataObjects\SPITransfer.
Example — read a register from an SPI peripheral
Example — chained, multi-segment transfer
spi_transfer accepts any number of SPITransfer segments. Each segment is sent back-to-back as a single SPI_IOC_MESSAGE transaction; CS is held low between segments unless a segment sets csChange: true.
See examples/as3935-autotune.php for a complete AS3935 antenna-autotune script that combines spi_transfer, GPIO edge events, and kernel hardware timestamps.
API Reference
Device lifecycle and I/O
| Helper | Facade method | Description |
|---|---|---|
spi_open(string $path, int $mode = 0, int $speed = 500_000, int $bitsPerWord = 8) |
Device::spiOpen |
Open /dev/spidev* and apply mode/speed/word-size; returns SPIDevice\|null |
spi_close(SPIDevice $dev) |
Device::spiClose |
Close the file descriptor; returns 0 or -1 |
spi_read(SPIDevice $dev, int $len) |
Device::spiRead |
Half-duplex read of up to $len bytes; returns string\|false |
spi_write(SPIDevice $dev, string $data) |
Device::spiWrite |
Half-duplex write of $data; returns bytes written |
spi_transfer(SPIDevice $dev, SPITransfer ...$transfers) |
Device::spiTransfer |
Full-duplex, chained transfer; returns concatenated MISO bytes or false |
spi_open validates each ioctl as it goes and closes the descriptor on any failure, so a non-null return guarantees the device is configured. The mode parameter is the same SPIMode bitmask the kernel uses (SPI_IOC_WR_MODE32).
Configuration (ioctl)
| Helper | Facade method | Underlying ioctl |
|---|---|---|
spi_get_mode(SPIDevice $dev) |
Device::spiGetMode |
SPI_IOC_RD_MODE32 |
spi_set_mode(SPIDevice $dev, int $mode) |
Device::spiSetMode |
SPI_IOC_WR_MODE32 |
spi_get_speed(SPIDevice $dev) |
Device::spiGetSpeed |
SPI_IOC_RD_MAX_SPEED_HZ |
spi_set_speed(SPIDevice $dev, int $hz) |
Device::spiSetSpeed |
SPI_IOC_WR_MAX_SPEED_HZ |
spi_get_bits_per_word(SPIDevice $dev) |
Device::spiGetBitsPerWord |
SPI_IOC_RD_BITS_PER_WORD |
spi_set_bits_per_word(SPIDevice $dev, int $bits) |
Device::spiSetBitsPerWord |
SPI_IOC_WR_BITS_PER_WORD |
spi_get_lsb_first(SPIDevice $dev) |
Device::spiGetLsbFirst |
SPI_IOC_RD_LSB_FIRST |
spi_set_lsb_first(SPIDevice $dev, bool $lsb) |
Device::spiSetLsbFirst |
SPI_IOC_WR_LSB_FIRST |
All setters return 0 on success and -1 on failure. Getters return the raw integer (or bool for lsb_first), and -1 on ioctl failure for the int-returning ones. Mask spi_get_mode against SPIMode cases to test individual mode bits.
Full-duplex transfers
spi_transfer(SPIDevice $dev, SPITransfer ...$transfers): string|false
Issues a single SPI_IOC_MESSAGE(n) ioctl bundling n transfer segments. CS is asserted at the start of the first segment and stays asserted across all segments unless an individual segment requests otherwise via csChange. Returns the concatenated MISO bytes from every segment (length equals the sum of each segment's len), or false if the transaction fails.
Two paths are supported transparently:
- Native fast path — if a low-level extension exposes
spi_transfer(int $fd, …)(note theintfirst argument), it is used directly. ext-posifallback — otherwise the call packs eachspi_ioc_transferstruct manually usingposi_mem_alloc/posi_mem_write/posi_mem_readand issuesSPI_IOC_MESSAGE(1)per segment. This is the supported path for plainext-posiinstallations.
If neither path is available, spi_transfer returns false.
Data objects
SPIDevice
The mode, speed, and bitsPerWord fields record the values passed to spi_open and are not updated when you later call spi_set_mode / spi_set_speed / spi_set_bits_per_word. Use the matching getter for the live kernel value.
SPITransfer
Notes:
$txis right-padded with NUL bytes if shorter than$len, and truncated if longer.- For read-only segments pass
tx: str_repeat("\0", $len)(or any dummy bytes — the slave ignores them on a pure read). csChangesemantics are inverted from intuition: setting ittruerequests CS de-assert after this segment, which is what you want for "this is the last byte of a logical message" inside a chain.- The dual/quad/octal lane fields require a controller and slave that support SPI multi-IO; leave them at
0for standard single-MOSI/MISO operation.
Enums
All enums are int-backed with SCREAMING_SNAKE_CASE cases that map directly to kernel constants.
SPIMode — mode bitmask (SPI_IOC_WR_MODE32)
| Case | Value | Meaning |
|---|---|---|
MODE_0 |
0x00 |
CPOL=0, CPHA=0 (alias of zero) |
CPHA |
0x01 |
Clock phase = 1 (sample on trailing edge) |
CPOL |
0x02 |
Clock polarity = 1 (idle high) |
CS_HIGH |
0x04 |
Chip-select is active-high |
LSB_FIRST |
0x08 |
LSB transmitted first |
THREE_WIRE |
0x10 |
Shared MOSI/MISO line |
LOOP |
0x20 |
Internal MOSI→MISO loopback |
NO_CS |
0x40 |
Disable hardware CS (manage manually) |
READY |
0x80 |
Slave pulls ready signal |
TX_DUAL |
0x100 |
Dual-lane MOSI |
RX_DUAL |
0x200 |
Dual-lane MISO |
TX_QUAD |
0x400 |
Quad-lane MOSI |
RX_QUAD |
0x800 |
Quad-lane MISO |
CS_WORD |
0x1000 |
Toggle CS per word |
TX_OCTAL |
0x2000 |
Octal-lane MOSI |
RX_OCTAL |
0x4000 |
Octal-lane MISO |
THREE_WIRE_HIZ |
0x8000 |
High-Z on inactive cycle of 3-wire |
The classical "SPI mode 0..3" values are simply CPOL/CPHA combinations:
| SPI mode | Bitmask | CPOL | CPHA |
|---|---|---|---|
| 0 | SPIMode::MODE_0->value (0) |
0 | 0 |
| 1 | SPIMode::CPHA->value (1) |
0 | 1 |
| 2 | SPIMode::CPOL->value (2) |
1 | 0 |
| 3 | SPIMode::CPOL->value \| SPIMode::CPHA->value (3) |
1 | 1 |
SPIOpCode — ioctl request numbers (<linux/spi/spidev.h>)
| Case | Value |
|---|---|
SPI_IOC_RD_MODE |
0x80016B01 |
SPI_IOC_WR_MODE |
0x40016B01 |
SPI_IOC_RD_LSB_FIRST |
0x80016B02 |
SPI_IOC_WR_LSB_FIRST |
0x40016B02 |
SPI_IOC_RD_BITS_PER_WORD |
0x80016B03 |
SPI_IOC_WR_BITS_PER_WORD |
0x40016B03 |
SPI_IOC_RD_MAX_SPEED_HZ |
0x80046B04 |
SPI_IOC_WR_MAX_SPEED_HZ |
0x40046B04 |
SPI_IOC_RD_MODE32 |
0x80046B05 |
SPI_IOC_WR_MODE32 |
0x40046B05 |
MESSAGE_1 |
0x40206B00 |
SPIOpCode::messageN(int $n): int computes the variant SPI_IOC_MESSAGE(n) ioctl number for batched transfers:
Quick reference
| Helper | Signature |
|---|---|
spi_open |
(string $path, int $mode = 0, int $speed = 500_000, int $bitsPerWord = 8): ?SPIDevice |
spi_close |
(SPIDevice $dev): int |
spi_read |
(SPIDevice $dev, int $len): string\|false |
spi_write |
(SPIDevice $dev, string $data): int |
spi_get_mode |
(SPIDevice $dev): int |
spi_set_mode |
(SPIDevice $dev, int $mode): int |
spi_get_speed |
(SPIDevice $dev): int |
spi_set_speed |
(SPIDevice $dev, int $hz): int |
spi_get_bits_per_word |
(SPIDevice $dev): int |
spi_set_bits_per_word |
(SPIDevice $dev, int $bits): int |
spi_get_lsb_first |
(SPIDevice $dev): bool |
spi_set_lsb_first |
(SPIDevice $dev, bool $lsb): int |
spi_transfer |
(SPIDevice $dev, SPITransfer ...$transfers): string\|false |
Notes
- Half-duplex vs full-duplex.
spi_readandspi_writeoperate on the kernel'sposix_read/posix_writepath, which is half-duplex — the kernel clocks out dummy bytes on a read and ignores MISO on a write. For real full-duplex transactions (where the bytes you receive correspond byte-for-byte to the bytes you transmit), usespi_transferwith one or moreSPITransfersegments. - CS behavior. A single
spi_transfercall holds CS low across every segment by default. SetcsChange: trueon a segment to release CS after it. UseSPIMode::NO_CSif your driver provides CS via a GPIO instead of the controller. - Word size on Linux. Most spidev drivers only support 8-bit words. Setting
bitsPerWordto anything else may return-1on platforms that don't support it. - Speed. The configured speed is an upper bound. The kernel rounds down to the closest divider the SPI controller can produce; query
spi_get_speedafterwards if exact-rate behavior matters. - Concurrency. Linux serialises access to a spidev character device per file descriptor. If you need overlapping transactions, open the same device twice — but the kernel will still serialise them on the bus.
License
MIT. See LICENSE.