Commit 12/08/2025
This commit is contained in:
157
src/sbc/DigitalOutput.kt
Normal file
157
src/sbc/DigitalOutput.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user