# sifangspitools **Repository Path**: egt/sifangspitools ## Basic Information - **Project Name**: sifangspitools - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-05 - **Last Updated**: 2026-08-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Android SPI Library 一个面向工业 Android 板卡的轻量 SPI 通讯库。Kotlin API 通过 JNI 调用 Linux `spidev`,底层使用 `SPI_IOC_MESSAGE` 完成全双工传输。 ## 工程结构 - `androidspi/`:可复用 Android Library,编译后生成 AAR。 - `app/`:最小示例 App,可输入设备节点和十六进制指令进行测试。 ## 使用条件 设备必须满足以下条件: 1. 内核开启 SPI 和 `spidev`。 2. 存在 `/dev/spidevX.Y`,例如 `/dev/spidev0.0`。 3. App 的 Linux UID 对设备节点具有读写权限。 4. SELinux 策略允许 App 域访问该设备节点。 5. 板卡的 Device Tree 和引脚复用配置正确。 先检查: ```bash adb shell ls -l /dev/spidev* adb shell ls -Z /dev/spidev0.0 ``` 普通消费级手机一般没有可用的 SPI 设备节点。本库主要面向 RK3568、RK3588、全志、NXP、工业平板、车机和其他定制 Android 设备。 ## Kotlin 调用 ```kotlin val config = SpiConfig( devicePath = "/dev/spidev0.0", mode = SpiMode.MODE_0, speedHz = 1_000_000, bitsPerWord = 8 ) LinuxSpiDevice.open(config).use { spi -> val response = spi.transfer( byteArrayOf(0x9F.toByte(), 0x00, 0x00, 0x00) ) Log.d("SPI", Hex.encode(response)) } ``` ## Java 调用 ```java SpiConfig config = new SpiConfig( "/dev/spidev0.0", SpiMode.MODE_0, 1_000_000, 8, false, 0 ); try (LinuxSpiDevice spi = LinuxSpiDevice.open(config)) { byte[] response = spi.transfer(new byte[] {(byte) 0x9F, 0, 0, 0}); Log.d("SPI", Hex.encode(response, " ")); } ``` ## Java 轮询读取 SPI 没有主动推送数据的监听机制。没有 IRQ/DREADY GPIO 时,需要由主设备定时发起传输。下面示例每 50ms 查询一次状态寄存器;当最低位为 1 时,再读取 8 个字节。`onPoll` 在后台线程执行,不能直接更新 UI。 ```java import android.util.Log; import io.github.lili.androidspi.LinuxSpiDevice; import io.github.lili.androidspi.SpiConfig; import io.github.lili.androidspi.SpiMode; import io.github.lili.androidspi.SpiPoller; SpiConfig config = new SpiConfig( "/dev/spidev0.0", SpiMode.MODE_0, 1_000_000, 8, false, 0 ); // 保存为 Activity/Service 的成员变量,不要在这里立即 close。 SpiPoller poller = SpiPoller.start(config, 50, new SpiPoller.Listener() { @Override public void onPoll(LinuxSpiDevice spi) { // 示例协议:0x05 是状态寄存器读命令,最低位表示有数据。 byte[] status = spi.transfer(new byte[] {0x05, 0x00}); boolean dataReady = (status[1] & 0x01) != 0; if (dataReady) { byte[] data = spi.read(8, (byte) 0x00); Log.d("SPI", "收到 " + data.length + " 字节"); // 这里解析 data;如果要更新界面,请切回主线程。 } } @Override public void onError(Throwable error) { Log.e("SPI", "轮询失败", error); } }); // Activity/Service 销毁时调用,停止线程并关闭 SPI 设备: // poller.close(); ``` 上例中的 `0x05`、最低位、读取长度 8 都只是示例,必须按你的 SPI 芯片协议手册修改。如果设备没有状态寄存器,也可以在 `onPoll` 中直接调用 `spi.read(...)`,但可能读到无效数据。 ## 生成 AAR 在 Android Studio 中打开根目录,然后执行: ```bash ./gradlew :androidspi:assembleRelease ``` 产物: ```text androidspi/build/outputs/aar/androidspi-release.aar ``` 对方项目可把 AAR 放入 `app/libs/`: ```kotlin dependencies { implementation(files("libs/androidspi-release.aar")) } ``` ## 发布到本机 Maven ```bash ./gradlew :androidspi:publishReleasePublicationToMavenLocal ``` 依赖坐标: ```kotlin implementation("io.github.lili:android-spi:1.0.0") ``` ## 当前能力 - SPI Mode 0/1/2/3 - 可配置时钟频率 - 可配置 bits per word - MSB/LSB first - 全双工 `transfer` - `read` / `write` 便捷方法 - Kotlin/Java 均可调用 - Java 后台轮询读取(`SpiPoller`) - 同一 `LinuxSpiDevice` 实例内线程安全 - native 错误包含 Linux errno 信息 ## 限制 - 当前一次调用对应一个 `spi_ioc_transfer`。 - 尚未提供多段消息、手动 GPIO CS、异步队列、CRC 和协议层。 - 权限与 SELinux 必须由系统镜像或设备厂商解决,普通 App 无法通过声明 Android 权限绕过。 ## 建议的设备端权限配置 不同厂商路径不同,通常需要同时处理: - `ueventd.rc`:设备节点 owner/group/mode - `sepolicy`:允许目标 App domain 访问 SPI 字符设备 - Device Tree:启用 SPI 控制器和 `spidev` 不建议正式项目通过 root 后执行 `chmod 666` 作为长期方案。 ## License Apache License 2.0