StandAPP/app/src/main/java/com/stand/standapp/utils/GpioManager.kt

122 lines
4.6 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.stand.standapp.utils
import android.app.ZysjSystemManager
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.stand.standapp.MainActivity
import com.stand.standapp.TempCallActivity
import timber.log.Timber
/**
* 硬件 GPIO 监听管理类 (用于物理 PTT 按键)
*/
object GpioManager {
private var mZysjSystemManager: ZysjSystemManager? = null
@Volatile
private var mIsRunning = false
private var mThread: Thread? = null
private var lastGpioValue = 1 // 默认松开状态 (1)
fun init(context: Context) {
if (mZysjSystemManager != null) return
try {
mZysjSystemManager = context.applicationContext.getSystemService("zysj") as? ZysjSystemManager
Timber.tag("GPIO").i("ZysjSystemManager initialized: ${mZysjSystemManager != null}")
} catch (e: Exception) {
Timber.tag("GPIO").e(e, "Failed to get ZysjSystemManager")
}
}
fun startListening() {
if (mIsRunning) return
mIsRunning = true
mThread = Thread {
Timber.tag("GPIO").i("Start GPIO listening thread")
while (mIsRunning) {
try {
// 硬件轮询频率优化150ms 既能保证响应速度,又能降低 CPU 消耗
Thread.sleep(150)
val manager = mZysjSystemManager ?: continue
// 获取 GPIO 1 的值 (0 按下, 1 松开)
val currentValue = manager.get_zysj_gpio_value(1)
if (currentValue != lastGpioValue) {
Timber.tag("GPIO").d("GPIO 1 Value changed: $lastGpioValue -> $currentValue")
handleGpioChange(currentValue)
lastGpioValue = currentValue
}
} catch (e: Exception) {
Timber.tag("GPIO").e(e, "Error in GPIO loop")
}
}
}.apply { start() }
}
fun stopListening() {
mIsRunning = false
mThread?.interrupt()
mThread = null
}
private var isSpeaking = false
private var lastSpeakTime = 0L
private val MIN_SPEAK_DURATION = 200L
private fun handleGpioChange(value: Int) {
// 切换到主线程处理逻辑,确保线程安全且方便使用 Handler
Handler(Looper.getMainLooper()).post {
if (value == 0) {
// 硬件按下 PTT
if (!isSpeaking) {
isSpeaking = true
lastSpeakTime = System.currentTimeMillis()
com.example.kingway.ptt.SendAtUtil.speakPlay()
Timber.tag("GPIO").d("PTT Speak Play (Hardware)")
// 统一使用 updatePttTalkStatus 更新 UI
MainActivity.executeJs("updatePttTalkStatus(true)")
// 同步 TempCallActivity
TempCallActivity.instance?.onGpioPressed()
Timber.tag("GPIO").d("Notified TempCallActivity: onGpioPressed")
} else {
Timber.tag("GPIO").w("GPIO pressed but isSpeaking already true — ignoring")
}
} else {
// 硬件松开 PTT
Timber.tag("GPIO").d("GPIO released, isSpeaking=%s", isSpeaking)
if (isSpeaking) {
val now = System.currentTimeMillis()
val duration = now - lastSpeakTime
if (duration < MIN_SPEAK_DURATION) {
val delay = MIN_SPEAK_DURATION - duration
Timber.tag("GPIO").d("Hardware speak duration too short ($duration ms), delaying release by $delay ms")
Handler(Looper.getMainLooper()).postDelayed({
realRelease()
}, delay)
} else {
realRelease()
}
}
}
}
}
private fun realRelease() {
if (isSpeaking) {
isSpeaking = false
com.example.kingway.ptt.SendAtUtil.speakRelease()
Timber.tag("GPIO").d("PTT Speak Release (Hardware)")
// 统一使用 updatePttTalkStatus 更新 UI
MainActivity.executeJs("updatePttTalkStatus(false)")
// 同步 TempCallActivity
TempCallActivity.instance?.onGpioReleased()
Timber.tag("GPIO").d("Notified TempCallActivity: onGpioReleased")
} else {
Timber.tag("GPIO").w("GPIO realRelease skipped: already released")
}
}
}