129 lines
4.9 KiB
Kotlin
129 lines
4.9 KiB
Kotlin
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: InterruptedException) {
|
||
Timber.tag("GPIO").i("GPIO thread interrupted, exiting gracefully")
|
||
break
|
||
} catch (e: Exception) {
|
||
Timber.tag("GPIO").e(e, "Error in GPIO loop")
|
||
}
|
||
}
|
||
}.apply { start() }
|
||
}
|
||
|
||
fun stopListening() {
|
||
mIsRunning = false
|
||
mThread?.interrupt()
|
||
mThread = null
|
||
mZysjSystemManager = null
|
||
isSpeaking = false
|
||
lastGpioValue = 1
|
||
Timber.tag("GPIO").i("GPIO listening stopped and state reset")
|
||
}
|
||
|
||
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")
|
||
}
|
||
}
|
||
}
|