230 lines
6.7 KiB
Kotlin
230 lines
6.7 KiB
Kotlin
package barix
|
|
|
|
import codes.Somecodes
|
|
import com.fasterxml.jackson.databind.JsonNode
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.delay
|
|
import kotlinx.coroutines.launch
|
|
import org.tinylog.Logger
|
|
import java.net.DatagramPacket
|
|
import java.net.DatagramSocket
|
|
import java.net.InetSocketAddress
|
|
import java.net.Socket
|
|
import java.nio.ByteBuffer
|
|
import java.util.function.Consumer
|
|
|
|
@Suppress("unused")
|
|
class BarixConnection(val index: UInt, var channel: String, val ipaddress: String, val port: Int = 5002) {
|
|
private var _bR: Int = 0
|
|
private var _sd: Int = 0
|
|
private var _vu: Int = 0
|
|
private var _onlinecounter = 0
|
|
private val inet = InetSocketAddress(ipaddress, port)
|
|
private val maxUDPsize = 1000
|
|
private var _tcp: Socket? = null
|
|
|
|
|
|
/**
|
|
* Buffer remain in bytes
|
|
*/
|
|
var bufferRemain: Int
|
|
get() = _bR
|
|
set(value) {
|
|
_bR = value
|
|
_onlinecounter = 5
|
|
}
|
|
|
|
/**
|
|
* Status data, 0 = playback idle, 1 = playback running
|
|
*/
|
|
var statusData: Int
|
|
get() = _sd
|
|
set(value) {
|
|
_sd = if (value < 0) 0 else if (value > 1) 1 else value
|
|
_onlinecounter = 5
|
|
}
|
|
|
|
/**
|
|
* VU level 0-100
|
|
*/
|
|
var vu: Int
|
|
get() = _vu
|
|
set(value) {
|
|
_vu = if (value < 0) 0 else if (value > 100) 100 else value
|
|
_onlinecounter = 5
|
|
}
|
|
|
|
/**
|
|
* TCP command socket for communication with this Barix device
|
|
*/
|
|
var commandsocket: Socket?
|
|
get() = _tcp
|
|
set(value){
|
|
_tcp = value
|
|
}
|
|
|
|
/**
|
|
* Decrement online counter, if counter reaches 0, the device is considered offline
|
|
*/
|
|
fun decrementOnlineCounter() {
|
|
if (_onlinecounter > 0) {
|
|
_onlinecounter--
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if Barix device is online
|
|
* @return true if online
|
|
*/
|
|
fun isOnline(): Boolean {
|
|
return _onlinecounter > 0
|
|
}
|
|
|
|
/**
|
|
* Check if Barix device is idle (not playing)
|
|
* @return true if idle
|
|
*/
|
|
fun isIdle() : Boolean{
|
|
return statusData == 0
|
|
}
|
|
|
|
/**
|
|
* Check if Barix device is playing
|
|
* @return true if playing
|
|
*/
|
|
fun isPlaying() : Boolean{
|
|
return statusData == 1
|
|
}
|
|
|
|
/**
|
|
* Send data to Barix device via UDP
|
|
* @param data The data to send
|
|
*/
|
|
fun SendData(data: ByteArray, cbOK: Consumer<String>, cbFail: Consumer<String>) {
|
|
if (data.isNotEmpty()) {
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
DatagramSocket().use{ udp ->
|
|
val bb = ByteBuffer.wrap(data)
|
|
while(bb.hasRemaining()){
|
|
try {
|
|
val chunk = ByteArray(if (bb.remaining() > maxUDPsize) maxUDPsize else bb.remaining())
|
|
bb.get(chunk)
|
|
//println("Buffer remain: $bufferRemain, sending chunk size: ${chunk.size}")
|
|
while(bufferRemain<chunk.size){
|
|
delay(10)
|
|
//println("Waiting until buffer enough..")
|
|
}
|
|
udp.send(DatagramPacket(chunk, chunk.size, inet))
|
|
delay(2)
|
|
} catch (e: Exception) {
|
|
cbFail.accept("SendData to $ipaddress failed, message: ${e.message}")
|
|
return@launch
|
|
}
|
|
}
|
|
cbOK.accept("SendData to $channel ($ipaddress) succeeded, ${data.size} bytes sent")
|
|
}
|
|
}
|
|
|
|
} else cbFail.accept("SendData to $ipaddress failed, data is empty")
|
|
|
|
}
|
|
|
|
/**
|
|
* Convert BarixConnection to JsonNode
|
|
* @return JsonNode representation of BarixConnection
|
|
*/
|
|
fun toJsonNode(): JsonNode {
|
|
// make json node from index, channel, ipaddress, port, bufferRemain, statusData, vu
|
|
return Somecodes.objectmapper.createObjectNode().apply {
|
|
put("index", index.toInt())
|
|
put("channel", channel)
|
|
put("ipaddress", ipaddress)
|
|
put("port", port)
|
|
put("bufferRemain", bufferRemain)
|
|
put("statusData", statusData)
|
|
put("vu", vu)
|
|
put("isOnline", isOnline())
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert BarixConnection to JSON string
|
|
* @return JSON string representation of BarixConnection
|
|
*/
|
|
fun toJsonString(): String {
|
|
return Somecodes.toJsonString(toJsonNode())
|
|
}
|
|
|
|
/**
|
|
* Activate relay on Barix device
|
|
* @param relays The relay numbers to activate (1-8)
|
|
* @return true if successful
|
|
*/
|
|
fun ActivateRelay(vararg relays: Int){
|
|
val command = StringBuilder("RELAY;")
|
|
var binary = 0
|
|
relays.forEach {
|
|
if (it in 1..8) {
|
|
binary = binary or (1 shl (it - 1))
|
|
}
|
|
}
|
|
command.append(binary.toString()).append("@")
|
|
SendCommand(command.toString())
|
|
}
|
|
|
|
fun ActivateRelay(relays: List<Int>){
|
|
val command = StringBuilder("RELAY;")
|
|
var binary = 0
|
|
relays.forEach {
|
|
if (it in 1..8) {
|
|
binary = binary or (1 shl (it - 1))
|
|
}
|
|
}
|
|
command.append(binary.toString()).append("@")
|
|
SendCommand(command.toString())
|
|
}
|
|
|
|
/**
|
|
* Deactivate relay on Barix device
|
|
*/
|
|
fun DeactivateRelay(){
|
|
SendCommand("RELAY;0@")
|
|
}
|
|
|
|
/**
|
|
* Send command to Barix device
|
|
* @param command The command to send
|
|
* @return true if successful
|
|
*/
|
|
fun SendCommand(command: String): Boolean {
|
|
try {
|
|
if (_tcp!=null){
|
|
if (!_tcp!!.isClosed){
|
|
val bb = command.toByteArray()
|
|
val size = bb.size + 4
|
|
val b4 = byteArrayOf(
|
|
(size shr 24 and 0xFF).toByte(),
|
|
(size shr 16 and 0xFF).toByte(),
|
|
(size shr 8 and 0xFF).toByte(),
|
|
(size and 0xFF).toByte()
|
|
)
|
|
val out = _tcp!!.getOutputStream()
|
|
out.write(b4)
|
|
out.write(bb)
|
|
out.flush()
|
|
Logger.info { "SendCommand to $ipaddress : $command" }
|
|
return true
|
|
}else {
|
|
Logger.error { "Socket to $ipaddress is not connected" }
|
|
}
|
|
} else {
|
|
Logger.error { "Socket to $ipaddress is null" }
|
|
}
|
|
|
|
} catch (e: Exception) {
|
|
Logger.error { "Failed to SendCommand to $ipaddress, Message : ${e.message}" }
|
|
}
|
|
return false
|
|
}
|
|
} |