Commit 12/08/2025

This commit is contained in:
2025-08-12 09:44:11 +07:00
parent f4c9fa8730
commit 60e8524c8f
33 changed files with 385 additions and 110 deletions

157
src/sbc/DigitalOutput.kt Normal file
View File

@@ -0,0 +1,157 @@
package sbc
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory
import somecodes.Codes.Companion.gpioExportPath
import somecodes.Codes.Companion.gpioPath
import somecodes.Codes.Companion.gpioUnexportPath
import somecodes.Codes.Companion.haveGpioSupport
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.isDirectory
/**
* Create a digital output for a GPIO pin.
* @param linuxGpio The GPIO pin number in Linux.
* @param name The name of the digital output.
* @param activeHigh If true, the output is active high (default is true).
* @property inited Indicates whether the digital output has been initialized.
*
*/
@Suppress("unused")
class DigitalOutput(val linuxGpio: Int, val name: String, val activeHigh: Boolean = true) {
var inited = false; private set
private var valuepath: Path? = null
private val logger = LoggerFactory.getLogger("DigitalOutput $name ($linuxGpio)")
init{
if (haveGpioSupport()){
if (checkExists()){
// already exists
try{
// try to set direction to output
val dir = gpioPath.resolve("gpio$linuxGpio").resolve("direction")
Files.writeString(dir, "out")
// successfully set direction to output
inited = true
valuepath = gpioPath.resolve("gpio$linuxGpio").resolve("value")
logger.info("GPIO $name GPIO $linuxGpio already exists as output")
} catch (e : Exception){
// failed to set direction to output, log error
logger.error("Failed to set existing GPIO $name GPIO $linuxGpio as output: ${e.message}")
}
} else {
// not yet exists, export it
try{
// export the GPIO pin
Files.writeString(gpioExportPath, linuxGpio.toString())
if (checkExists()){
// successfully exported, now set direction to output
val dir = gpioPath.resolve("gpio$linuxGpio").resolve("direction")
Files.writeString(dir, "out")
inited = true
valuepath = gpioPath.resolve("gpio$linuxGpio").resolve("value")
logger.info("Initialized GPIO $name GPIO $linuxGpio as output")
} else {
// failed to export, log error
logger.error("GPIO $name GPIO $linuxGpio does not exist after export")
}
} catch (e: Exception){
// failed to export GPIO pin, log error
logger.error("Failed to export GPIO $name GPIO $linuxGpio: ${e.message}")
}
}
} else logger.error("DigitalOutput $name GPIO $linuxGpio not initialized: GPIO support not available")
}
fun checkExists(): Boolean{
return try {
val gpioPath = gpioPath.resolve("gpio$linuxGpio")
if (gpioPath.isDirectory() && gpioPath.toFile().exists()){
val dir = gpioPath.resolve("direction").toFile()
val value = gpioPath.resolve("value").toFile()
if (dir.exists() && value.exists()) {
return dir.canWrite() && value.canWrite()
}
}
false
} catch (e: Exception) {
logger.error("Error checking if GPIO $linuxGpio exists: ${e.message}")
false
}
}
/**
* Release the GPIO pin by unexporting it.
*/
fun release(){
if (inited){
try{
Files.writeString(gpioUnexportPath, linuxGpio.toString())
inited = false
valuepath = null
} catch (e : Exception){
logger.error("Failed to unexport GPIO $name GPIO ${e.message}")
}
}
}
/**
* Set Digital Output to ON
*/
fun setON() : Boolean{
if (inited){
if (valuepath!=null){
try{
Files.writeString(valuepath!!, if (activeHigh) "1" else "0")
return true
} catch (e: Exception){
logger.error("Failed to set GPIO $name GPIO $linuxGpio ON: ${e.message}")
}
}
}
return false
}
/**
* Set Digital Output to OFF
*/
fun setOFF() : Boolean{
if (inited){
if (valuepath!=null){
try{
Files.writeString(valuepath!!, if (activeHigh) "0" else "1")
return true
} catch (e : Exception){
logger.error("Failed to set GPIO $name GPIO $linuxGpio OFF: ${e.message}")
}
}
}
return false
}
/**
* Blink the Digital Output for a specified duration.
* @param ms The duration in milliseconds to keep the output ON before turning it OFF (default is 50ms).
*/
fun Blink(ms: Long = 50){
if (inited){
CoroutineScope(Dispatchers.IO).launch {
setON()
delay(ms)
setOFF()
}
}
}
}