microscrap/usb-drivers 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

microscrap/usb-drivers

Composer 安装命令:

composer require microscrap/usb-drivers

包简介

The Official ScrapyardIO USB Drivers package.

README 文档

README

PHP driver package that provides the usb carrier for the ScrapyardIO framework GPIO stack. It drives FTDI USB adapters (FT232H, FT2232HL, FT232RL) through ext-ftdi, tunnelling SPI, I²C, and digital GPIO over MPSSE and running UART as plain async serial.

This package includes:

  • The ScrapyardIOUSBManager carrier manager, auto-discovered by the framework via the #[CarrierDriver('usb')] attribute
  • MPSSE-backed protocol drivers for SPI, I²C, and digital input/output
  • A libftdi-backed UART driver (no MPSSE) for serial-only workflows
  • Digital pin ride-along on SPI/I²C buses — control DC/RESET/BUSY pins on the same FTDI adapter that carries the bus

Requirements

  • PHP 8.3+
  • ext-ftdi ^0.4.2 — the PHP FTDI extension (requires libftdi1 at runtime)
    • Debian/Ubuntu/Raspberry Pi OS: libftdi1-2 (dev package for builds: libftdi1-dev)
    • macOS: brew install libftdi
  • microscrap/ftdi ^0.5.0 — global ftdi_* helpers (installed automatically)
  • microscrap/mpsse ^0.5.0 — required for SPI, I²C, and digital GPIO (suggested; UART works without it)

Currently Supported devices

Device MPSSE device() value (SPI/I²C/GPIO) UART device() value Product ID
FT232H ft232h FtdiProductId::FT232H->value 0x6014
FT2232HL ft2232hl-a (channel A) / ft2232hl-b (channel B) FtdiProductId::FT2232HL->value 0x6010
FT232RL — (no MPSSE engine) FtdiProductId::RS232L->value 0x6001

Note, these are the only devices so far I've tested. There shouldn't be any reason why any other MPSSE-enabled devices wouldn't work if there is a valid product id hex for the device. You could make a pull request with the missing device, or use custom logic that doesn't use the MpsseSupportedDevices enum.

The two protocol families address devices differently:

  • SPI / I²C / GPIO go through Microscrap\Bindings\MPSSE\Enums\MpsseSupportedDevice, which picks the exact MPSSE engine (channel A or B) and its product ID together. The FT2232HL has two independent MPSSE engines, so ft2232hl-a and ft2232hl-b are addressed separately.
  • UART goes through Microscrap\Bindings\FTDI\Enums\FtdiProductId, which is only the raw product ID — there is one UART per chip regardless of how many MPSSE engines it has, so the FT2232HL is addressed as a single FtdiProductId::FT2232HL, not per channel.

Installation

Install the FTDI extension first (see php-io-extensions/ftdi):

pie install php-io-extensions/ftdi

Confirm it is loaded:

php -m | grep ftdi

Install the driver package:

composer require microscrap/usb-drivers

If your workflow includes SPI, I²C, or digital GPIO (anything other than UART), install the MPSSE package as well:

composer require microscrap/mpsse

The manager enforces these prerequisites at runtime and throws a GPIOException with install instructions when one is missing.

How it works

The framework resolves the usb carrier through attribute-based discovery — no manual registration:

GPIO::spi('usb')->…->create()
  └─ SPIConnectionFactory            (scrapyard-io/framework)
       └─ GPIOCarriers::usb('spi')
            └─ ScrapyardIOUSBManager  (#[CarrierDriver('usb')], this package)
                 └─ MPSSESPIDriver
                      └─ microscrap/mpsse → microscrap/ftdi → ext-ftdi → libftdi1

Each GPIO protocol maps to a driver in this package:

Protocol Driver Backend
spi MPSSESPIDriver MPSSE, modes SPI0–SPI3
i2c MPSSEI2CDriver MPSSE with full ACK/NACK sequencing
digital-in MPSSEDigitalInputDriver MPSSE GPIO mode, polled edge events
digital-out MPSSEDigitalOutputDriver MPSSE GPIO mode
uart FTDIUartDriver Plain async serial via ftdi_* helpers — no MPSSE

UART is intentionally kept off MPSSE: FTDIUartDriver resets the chip to async-serial bitmode on open (ftdi_set_bitmode($context, 0x00, 0x00)) so that multi-protocol parts like the FT232H release D0/D1 back to TX/RX even if a previous session left MPSSE enabled.

Usage

All examples go through the framework's GPIO facade with the usb driver.

SPI

<?php

use GPIO\Common\GPIO;
use GPIO\Contracts\SPI\SPIMode;

$spi = GPIO::spi('usb')
    ->device('ft232h')
    ->mode(SPIMode::MODE_0)
    ->speed(1_000_000)
    ->create();

$spi->write("\x9F");                          // clock bytes out
$jedec = $spi->transfer("\x9F\x00\x00\x00");  // full-duplex transfer
$bytes = $spi->read(3);                       // clock bytes in

$spi->close();

I²C

<?php

use GPIO\Common\GPIO;

$i2c = GPIO::i2c('usb')
    ->device('ft232h')
    ->slave(0x26)
    ->create();

$who_am_i = $i2c->writeRead("\x01", 1);  // write register address, repeated START, read 1 byte
$i2c->write([0x11, 0x40]);               // write register + value
$data = $i2c->read(2);                   // plain read

$i2c->close();

UART

UART devices are addressed by FTDI product ID, not by MPSSE device name:

<?php

use GPIO\Common\GPIO;
use Microscrap\Bindings\FTDI\Enums\FtdiProductId;

$uart = GPIO::uart('usb')
    ->device(FtdiProductId::RS232L->value)  // 0x6001 — FT232RL
    ->baud(115200)
    ->create();

$uart->write("AT\r\n");
$response = $uart->read(64);  // byte array, or false when nothing arrived

$uart->flush();
$uart->close();

The same call works on a FT2232HL — pass FtdiProductId::FT2232HL->value instead of an ft2232hl-a / ft2232hl-b MPSSE string, since the chip exposes only one UART regardless of channel:

$uart = GPIO::uart('usb')
    ->device(FtdiProductId::FT2232HL->value)  // 0x6010
    ->baud(115200)
    ->create();

baud(), parity(), stopBits(), dataBits(), and flowControl() are all available on the factory; defaults are 9600 8N1 with no flow control.

Digital output

GPIO mode exposes 12 lines per MPSSE device — MPSSEGpioPin::GPIOL0GPIOL3 (pins 0–3) and GPIOH0GPIOH7 (pins 4–11):

<?php

use GPIO\Common\GPIO;
use Microscrap\Bindings\MPSSE\Enums\MPSSEGpioPin;

$led = GPIO::digitalOut('usb')
    ->device('ft232h')
    ->pin(MPSSEGpioPin::GPIOL1->value)
    ->name('led')
    ->defaultState(false)
    ->create();

$led->high();
$led->low();

$led->close();

Digital input

<?php

use GPIO\Common\GPIO;

$button = GPIO::digitalIn('usb')
    ->device('ft232h')
    ->pin(0)
    ->name('button')
    ->withEvents(true, false)  // rising, falling
    ->timeout(5000)            // ms
    ->create();

$event = $button->listen();     // ?DigitalInputEvent — blocks up to the timeout
$pressed = $button->isHigh();   // immediate level read

$button->close();

Edge detection is polling-based (the FTDI adapter has no interrupt lines), sampling roughly every millisecond until the timeout elapses.

Digital pins on a SPI/I²C bus

Displays and similar chips need DC/RESET/BUSY pins alongside the bus. Attach them to the same MPSSE context and get a connection bus back:

<?php

use GPIO\Common\GPIO;
use GPIO\Contracts\SPI\SPIMode;
use GPIO\Contracts\Digital\LineBias;

$bus = GPIO::spi('usb')
    ->device('ft232h')
    ->mode(SPIMode::MODE_0)
    ->speed(1_000_000)
    ->digitalPins()
    ->digitalOut(pin: 4, name: 'dc', default_state: false)
    ->digitalIn(pin: 5, name: 'busy', events: [false, true], timeout: 1000, bias: LineBias::AS_IS)
    ->create();  // SPIConnectionBus

$bus->getPin('dc')->high();
$bus->spi->write("\x2A");

while ($bus->getPin('busy')->isHigh()) {
    usleep(1_000);
}

The same pattern works for I²C (I2CConnectionBus, with the transport on $bus->i2c).

Exceptions

Exception Extends Thrown when
MpsseUSBException GPIOException An MPSSE device context cannot be opened (includes the FTDI error string)
FTDIUARTException UARTException A UART device fails to open (includes the FTDI error string)
UARTException The factory's device() was never set (missingMasterDevice)
GPIOException ext-ftdi, microscrap/ftdi, or microscrap/mpsse is missing, or a driver does not extend ScrapyardIOUSBDriver

Note that passing an unknown product ID to GPIO::uart('usb')->device(...) fails inside FtdiProductId::from() with a PHP ValueError before any exception above is reached.

Testing (Pest v4)

Run the suite:

./vendor/bin/pest

The unit tests run without hardware — FTDI and MPSSE globals are replaced with in-memory fakes and spies (tests/Support/), so driver dispatch, MPSSE call ordering, and error paths are all exercised on any machine.

License

MIT. See LICENSE.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-06

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固