commit 14/01/2026
This commit is contained in:
@@ -185,6 +185,14 @@ class Somecodes {
|
||||
return Path.of(path).fileName.toString()
|
||||
}
|
||||
|
||||
fun ToByteArray(vararg values: Int) : ByteArray {
|
||||
val byteArray = ByteArray(values.size)
|
||||
for (i in values.indices){
|
||||
byteArray[i] = values[i].toByte()
|
||||
}
|
||||
return byteArray
|
||||
}
|
||||
|
||||
fun ExtractFilesFromClassPath(resourcePath: String, outputDir: Path) {
|
||||
try {
|
||||
val resource = Somecodes::class.java.getResource(resourcePath)
|
||||
|
||||
24
src/toa/SX2KBroadcastFromAI.kt
Normal file
24
src/toa/SX2KBroadcastFromAI.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package toa
|
||||
|
||||
@Suppress("unused")
|
||||
data class SX2KBroadcastFromAI(val AIAddress: Int, val AIChannel: Int, val Zone: ByteArray = ByteArray(32)){
|
||||
init {
|
||||
require(AIAddress in 1..8 ) { "AIAddress must be in the range 1-8" }
|
||||
require(AIChannel in 1..8) { "AIChannel must be in the range 8-8" }
|
||||
}
|
||||
fun ZoneSelect(AO: Int, ZoneNumber: Int, Broadcast: Boolean){
|
||||
if (AO in 1..32 && ZoneNumber in 1..8){
|
||||
val index = (AO - 1)
|
||||
val bit = ZoneNumber - 1
|
||||
if (Broadcast){
|
||||
Zone[index] = (Zone[index].toInt() or (1 shl bit)).toByte()
|
||||
} else {
|
||||
Zone[index] = (Zone[index].toInt() and (1 shl bit).inv()).toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "SX2KBroadcastFromAI(AISlot=$AIAddress, AIChannel=$AIChannel)"
|
||||
}
|
||||
}
|
||||
28
src/toa/SX2KCIN.kt
Normal file
28
src/toa/SX2KCIN.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package toa
|
||||
|
||||
data class SX2KCIN(val device: SX2KDevice, val address: Int, val Cin: Int, val state: Boolean) {
|
||||
init{
|
||||
when(device){
|
||||
SX2KDevice.SX2000SM -> {
|
||||
require(Cin in 1..8) { "Cin must be between 1 and 8 for SX2000SM" }
|
||||
}
|
||||
SX2KDevice.SX2000AO -> {
|
||||
require(address in 1..32) { "Address must be between 1 and 32 for SX2000AO" }
|
||||
require(Cin in 1..8) { "Cin must be between 1 and 8 for SX2000AO" }
|
||||
}
|
||||
SX2KDevice.SX2000AI -> {
|
||||
require(address in 1..8) { "Address must be between 1 and 8 for SX2000AI" }
|
||||
require(Cin in 1..16) { "Cin must be between 1 and 16 for SX2000AI" }
|
||||
}
|
||||
else -> throw IllegalArgumentException("Invalid device type")
|
||||
}
|
||||
}
|
||||
override fun toString(): String {
|
||||
return when(device){
|
||||
SX2KDevice.SX2000SM -> "SX2000SM - Cin: $Cin, State: $state"
|
||||
SX2KDevice.SX2000AO -> "SX2000AO - Address: $address, Cin: $Cin, State: $state"
|
||||
SX2KDevice.SX2000AI -> "SX2000AI - Address: $address, Cin: $Cin, State: $state"
|
||||
else -> "Unknown Device"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/toa/SX2KDevice.kt
Normal file
10
src/toa/SX2KDevice.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package toa
|
||||
|
||||
@Suppress("unused")
|
||||
enum class SX2KDevice(description: String) {
|
||||
SX2000SM("SX2000SM"),
|
||||
SX2000AI("SX2000AI"),
|
||||
SX2000AO("SX2000AO"),
|
||||
SX2000CI("SX2000CI"),
|
||||
SX2000CO("SX2000CO")
|
||||
}
|
||||
159
src/toa/Sx2K.kt
Normal file
159
src/toa/Sx2K.kt
Normal file
@@ -0,0 +1,159 @@
|
||||
package toa
|
||||
|
||||
import codes.Somecodes.Companion.ToByteArray
|
||||
import org.tinylog.Logger
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
|
||||
/**
|
||||
* Created by a Sx2K device.
|
||||
* @param ipAddress The IP address of the Sx2K device. Default is 192.168.14.1
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class Sx2K(val ipAddress: String = "192.168.14.1") {
|
||||
private var remotesocket : InetSocketAddress? = null
|
||||
private val timeout = 2000
|
||||
init {
|
||||
try{
|
||||
val inet = InetSocketAddress(ipAddress, 2005)
|
||||
// connect trial
|
||||
val socket = Socket()
|
||||
socket.soTimeout = 2000
|
||||
socket.connect(inet, 2000)
|
||||
socket.close()
|
||||
remotesocket = inet
|
||||
} catch (e: Exception) {
|
||||
Logger.error { "Invalid IP address: $ipAddress , exception : ${e.message}" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a BroadcastFromAI on the Sx2K device.
|
||||
* @param Broadcast Vararg of SX2KBroadcastFromAI objects to start the broadcast
|
||||
*/
|
||||
fun StartBroadcastFromAI(vararg Broadcast: SX2KBroadcastFromAI){
|
||||
if (remotesocket == null) {
|
||||
Logger.error { "Cannot create BroadcastFromAI, invalid Sx2K device IP address: $ipAddress" }
|
||||
return
|
||||
}
|
||||
try{
|
||||
Socket().use { socket ->
|
||||
socket.connect(remotesocket, timeout)
|
||||
socket.soTimeout = timeout
|
||||
val outputStream = socket.getOutputStream()
|
||||
val inputStream = socket.getInputStream()
|
||||
Broadcast.forEach { bc ->
|
||||
val cmd : ByteArray = ToByteArray(0xA0, 0xAD, bc.AIAddress, bc.AIChannel) + bc.Zone
|
||||
outputStream.write(cmd)
|
||||
outputStream.flush()
|
||||
val reply = ByteArray(2)
|
||||
inputStream.read(reply)
|
||||
if (reply[0]==0.toByte() && reply[1]==1.toByte()){
|
||||
// DONE TRUE
|
||||
Logger.info { "BroadcastFromAI succeeded for $bc" }
|
||||
} else {
|
||||
Logger.error { "BroadcastFromAI failed for $bc" }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.error { "BroadcastFromAI failed , exception : ${e.message}" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a BroadcastFromAI on the Sx2K device.
|
||||
* @param Broadcast Vararg of SX2KBroadcastFromAI objects to stop the broadcast
|
||||
*/
|
||||
fun StopBroadcastFromAI(vararg Broadcast: SX2KBroadcastFromAI){
|
||||
if (remotesocket == null) {
|
||||
Logger.error { "Cannot create StopBroadcastFromAI, invalid Sx2K device IP address: $ipAddress" }
|
||||
return
|
||||
}
|
||||
try{
|
||||
Socket().use { socket ->
|
||||
socket.connect(remotesocket, timeout)
|
||||
socket.soTimeout = timeout
|
||||
val outputStream = socket.getOutputStream()
|
||||
val inputStream = socket.getInputStream()
|
||||
Broadcast.forEach { bc ->
|
||||
val cmd = ToByteArray(0xA1, 0xAD, bc.AIAddress, bc.AIChannel)
|
||||
outputStream.write(cmd)
|
||||
outputStream.flush()
|
||||
val reply = ByteArray(2)
|
||||
inputStream.read(reply)
|
||||
if (reply[0]==0.toByte() && reply[1]==1.toByte()){
|
||||
// DONE TRUE
|
||||
Logger.info { "StopBroadcastFromAI succeeded for $bc" }
|
||||
} else {
|
||||
Logger.error { "StopBroadcastFromAI failed for $bc" }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.error { "StopBroadcastFromAI failed , exception : ${e.message}" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of virtual contact inputs on the Sx2K device.
|
||||
* @param cin Vararg of SX2KCIN objects to set the state
|
||||
*/
|
||||
fun VirtualContactInput(vararg cin : SX2KCIN){
|
||||
if (remotesocket == null) {
|
||||
Logger.error { "Cannot create VirtualContactInput, invalid Sx2K device IP address: $ipAddress" }
|
||||
return
|
||||
}
|
||||
try {
|
||||
Socket().use { socket ->
|
||||
socket.connect(remotesocket, timeout)
|
||||
socket.soTimeout = timeout
|
||||
val outputStream = socket.getOutputStream()
|
||||
val inputStream = socket.getInputStream()
|
||||
cin.forEach { cc ->
|
||||
val cmd : ByteArray = when(cc.device){
|
||||
SX2KDevice.SX2000SM -> {
|
||||
if (cc.Cin in 1..8){
|
||||
ToByteArray(0xA0, 0xA0, cc.Cin, if (cc.state) 0x01 else 0x00)
|
||||
} else ByteArray(0)
|
||||
}
|
||||
SX2KDevice.SX2000AO -> {
|
||||
if (cc.address in 1..32){
|
||||
if (cc.Cin in 1..8){
|
||||
ToByteArray(0xA0, 0xA1, cc.address, cc.Cin, if (cc.state) 0x01 else 0x00)
|
||||
} else ByteArray(0)
|
||||
} else ByteArray(0)
|
||||
}
|
||||
SX2KDevice.SX2000AI -> {
|
||||
if (cc.address in 1..8){
|
||||
if (cc.Cin in 1..16){
|
||||
ToByteArray(0xA0, 0xA2, cc.address, cc.Cin, if (cc.state) 0x01 else 0x00)
|
||||
} else ByteArray(0)
|
||||
} else ByteArray(0)
|
||||
}
|
||||
else -> ByteArray(0)
|
||||
}
|
||||
if (cmd.isNotEmpty()){
|
||||
outputStream.write(cmd)
|
||||
outputStream.flush()
|
||||
val reply = ByteArray(2)
|
||||
inputStream.read(reply)
|
||||
if (reply[0]==0.toByte() && reply[1]==1.toByte()){
|
||||
// DONE TRUE
|
||||
Logger.info { "VirtualContactInput succeeded for $cc" }
|
||||
} else {
|
||||
Logger.error { "VirtualContactInput failed for $cc" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (e : Exception){
|
||||
Logger.error { "VirtualContactInput failed , exception : ${e.message}" }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import codes.Somecodes
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.tinylog.Logger
|
||||
import java.net.Inet4Address
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
@@ -17,6 +16,7 @@ import java.util.function.BiConsumer
|
||||
* @param ipaddress IP address of the VX3K device, default to 192.168.14.1
|
||||
* @param port Port number of the VX3K device, from 50050-50053 default to 50053
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class Vx3K(val ipaddress : String = "192.168.14.1", val port : Int = 50053) {
|
||||
private val remotesocket : InetSocketAddress
|
||||
init{
|
||||
@@ -31,21 +31,6 @@ class Vx3K(val ipaddress : String = "192.168.14.1", val port : Int = 50053) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the VX3K device
|
||||
* @param timeout Connection timeout in milliseconds, default to 30000 ms
|
||||
*/
|
||||
fun Connect(timeout: Int = 30000){
|
||||
try{
|
||||
val socket = Socket()
|
||||
// read timeout 5 seconds
|
||||
socket.soTimeout = 5000
|
||||
socket.connect(remotesocket, timeout)
|
||||
} catch (e : Exception){
|
||||
Logger.error { "Failed to connect with ${remotesocket.hostName}:${remotesocket.port}, Message: ${e.message}" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual Contact Input (Commmand 0x1001)
|
||||
* @param ID : Device ID for VX3K, range 0 - 31
|
||||
@@ -226,7 +211,7 @@ class Vx3K(val ipaddress : String = "192.168.14.1", val port : Int = 50053) {
|
||||
try{
|
||||
val tcp = Socket()
|
||||
tcp.soTimeout = 5000
|
||||
tcp.connect(remotesocket, 30000)
|
||||
tcp.connect(remotesocket, 5000)
|
||||
val outstream = tcp.getOutputStream()
|
||||
val instream = tcp.getInputStream()
|
||||
outstream.write(command)
|
||||
|
||||
Reference in New Issue
Block a user