Files
FAtoPA/VX3K.cs
2024-11-21 07:47:06 +07:00

362 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace FAtoPA
{
class VX3K
{
public static bool Started = false;
private String targetip = "192.168.14.1";
private UInt16 targetport = 5000;
private TcpClient? socket;
// Statistics
public uint TXBytes { get; private set; } = 0;
public uint RXBytes { get; private set; } = 0;
public uint TXOK { get; private set; } = 0;
public uint RXOK { get; private set; } = 0;
public uint TXErr { get; private set; } = 0;
public uint RXErr { get; private set; } = 0;
private readonly EventInterface _event;
public VX3K(EventInterface callback){
this._event = callback;
}
/// <summary>
/// Connect to VX-3000
/// </summary>
/// <param name="ipaddress">target IP address, default to 192.168.14.1</param>
/// <param name="port">target port, default to 5000</param>
public Boolean Connect(String ipaddress, UInt16 port)
{
TXBytes = 0;
RXBytes = 0;
TXOK = 0;
RXOK = 0;
TXErr = 0;
RXErr = 0;
raise_statistic();
if (ipaddress!=null && ipaddress.Length>0)
{
targetip=ipaddress;
raise_log("Target IP changed to " + targetip);
}
if (port>0 && port<65535)
{
targetport=port;
raise_log("Target Port changed to " + targetport);
}
try
{
TcpClient newclient = new TcpClient();
bool success = newclient.ConnectAsync(targetip, targetport).Wait(1000);
if (success && newclient.Connected)
{
socket = newclient;
raise_connect_status(true, "Connected to " + targetip + ":" + targetport);
return true;
}
else raise_connect_status(false, "Failed to connect to " + targetip + ":" + targetport);
} catch(Exception e)
{
raise_connect_status(false, "Error: " + e.Message);
}
return false;
}
/// <summary>
/// Check if connected to VX-3000
/// </summary>
/// <returns>true if connected</returns>
public Boolean IsConnected()
{
if (socket != null)
{
return socket.Connected;
}
return false;
}
/// <summary>
/// Disconnect from VX-3000
/// </summary>
public void Disconnect()
{
if (socket != null)
{
socket.Close();
socket = null;
raise_connect_status(false, "Disconnected from " + targetip + ":" + targetport);
}
else raise_connect_status(false, "Not connected yet");
}
/// <summary>
/// Set Virtual Contact Input ON/OFF <br/>
/// Contact Input ID : <br/>
/// 0 - 15 : Contact Input 1 - 16 <br/>
/// 16 : Emergency Contact input 1 <br/>
/// 17 : Emergency Contact input 2 <br/>
/// </summary>
/// <param name="vxID">VX Frame ID</param>
/// <param name="CinID">Contact Input ID</param>
/// <param name="isON">true = ON, false = OFF</param>
/// <returns></returns>
public Boolean Virtual_Contact_Input(UInt16 vxID, UInt16 CinID, Boolean isON)
{
byte[] payload = new byte[6];
payload[0] = HighByte(vxID);
payload[1] = LowByte(vxID);
payload[2] = HighByte(CinID);
payload[3] = LowByte(CinID);
payload[4] = 0x00;
payload[5] = (byte)(isON ? 0x01 : 0x00);
byte[] cmd = make_header_request_command(0x1001, payload);
if (SendCommand(cmd))
{
byte[] response = ReadResponse();
if (GetCommandCode(response) == 0x1001)
{
if (GetResponseCode(response) == 0x0000)
{
raise_log("Virtual Contact Input Command Success");
return true;
} else raise_log("Virtual Contact Input Command Failed, Invalid Response Code");
} else raise_log("Virtual Contact Input Command Failed, Invalid Command Code");
}
return false;
}
/// <summary>
/// Sending command to VX-3000
/// </summary>
/// <param name="cmd">Array of bytes containing command</param>
/// <returns>true if success</returns>
private Boolean SendCommand(byte[] cmd)
{
if (IsConnected() && socket != null)
{
if (cmd != null && cmd.Length > 0)
{
try
{
NetworkStream stream = socket.GetStream();
stream.Write(cmd, 0, cmd.Length);
TXBytes += (uint)cmd.Length;
TXOK++;
raise_statistic();
return true;
}
catch (Exception e)
{
raise_log("SendCommand failed, Error : "+e);
}
}
else raise_log("SendCommand failed, Invalid Command");
}
else raise_log("SendCommand failed, Not Connected to VX-3000");
TXErr++;
raise_statistic();
return false;
}
/// <summary>
/// Reading response from VX-3000
/// </summary>
/// <returns>array of bytes containing response , or empty array if failed</returns>
private byte[] ReadResponse()
{
if (IsConnected() && socket != null)
{
try
{
NetworkStream stream = socket.GetStream();
byte[] response = new byte[1500];
int bytes = stream.Read(response, 0, response.Length);
RXBytes += (uint)bytes;
RXOK++;
raise_statistic();
byte[] result = new byte[bytes];
Array.Copy(response, result, bytes);
return result;
}
catch (Exception e)
{
raise_log("ReadResponse failed, Error : " + e);
}
}
else raise_log("ReadResponse failed, Not Connected to VX-3000");
RXErr++;
raise_statistic();
return Array.Empty<byte>();
}
/// <summary>
/// Create VX-3000 command bytes
/// </summary>
/// <param name="command">command code</param>
/// <param name="payload">payload to send</param>
/// <returns>array of bytes</returns>
private byte[] make_header_request_command(UInt16 command, byte[] payload)
{
UInt16 cmdlen = 8;
if (payload != null && payload.Length > 0) cmdlen += (UInt16)payload.Length;
byte[] header = new byte[cmdlen];
header[0] = HighByte(command);
header[1] = LowByte(command);
header[2] = 0x00;
header[3] = 0x00;
header[4] = HighByte(cmdlen);
header[5] = LowByte(cmdlen);
header[6] = 0x80; // request to VX3000
header[7] = 0x00;
if (payload == null) return header; // no payload
if (payload.Length == 0) return header; // no payload
for(int i=0; i<payload.Length; i++)
{
header[8 + i] = payload[i];
}
return header;
}
/// <summary>
/// Return High Byte of a 16-bit value
/// </summary>
/// <param name="value">16 bit value</param>
/// <returns>Byte value</returns>
private byte HighByte(UInt16 value)
{
return (byte)((value >> 8) & 0xFF);
}
/// <summary>
/// Return Low Byte of a 16-bit value
/// </summary>
/// <param name="value">16 bit value</param>
/// <returns> Byte value</returns>
private byte LowByte(UInt16 value)
{
return (byte)(value & 0xFF);
}
/// <summary>
/// Get Command Code from response
/// Command Code value is Big-Endian UInt16 from index 0 and 1
/// </summary>
/// <param name="value">array of byte from Response</param>
/// <returns>Command Code or 0 if failed</returns>
private UInt16 GetCommandCode(byte[] value)
{
if (value != null && value.Length >= 2)
{
return (UInt16)((value[0] << 8) | value[1]);
}
return 0;
}
/// <summary>
/// Get Response Code from response
/// Response Code value is Big-Endian UInt16 from index 2 and 3
/// </summary>
/// <param name="value">array of byte from Response</param>
/// <returns>Response Code or 0 if failed</returns>
private UInt16 GetResponseCode(byte[] value)
{
if (value != null && value.Length >= 4)
{
return (UInt16)((value[2] << 8) | value[3]);
}
return 0;
}
/// <summary>
/// Get Command Length from response
/// Command Length value is Big-Endian UInt16 from index 4 and 5
/// </summary>
/// <param name="value">array of byte from Response</param>
/// <returns>Command Length or 0 if failed</returns>
private UInt16 GetCommandLength(byte[] value)
{
if (value != null && value.Length >= 6)
{
return (UInt16)((value[4] << 8) | value[5]);
}
return 0;
}
/// <summary>
/// Get Command Flag from response
/// Command Flag value is Byte at index 6
/// </summary>
/// <param name="value">array of byte from Response</param>
/// <returns>Command Flag or 0 if failed</returns>
private byte GetCommandFlag(byte[] value)
{
if (value != null && value.Length >= 7)
{
return value[6];
}
return 0;
}
/// <summary>
/// Get Payload from Response
/// Payload is located at index 8 to end of array
/// </summary>
/// <param name="value">array of byte from Response</param>
/// <returns>Payload bytes or empty array if failed</returns>
private byte[] GetPayload(byte[] value)
{
if (value != null && value.Length > 8)
{
if ((GetCommandFlag(value) & 0x40) != 0)
{
byte[] payload = new byte[value.Length - 8];
Array.Copy(value, 8, payload, 0, payload.Length);
return payload;
}
}
return Array.Empty<byte>();
}
private void raise_log(String msg)
{
if (_event!=null) _event.Log(msg);
}
private void raise_statistic()
{
if (_event != null) _event.StatisticUpdate(TXOK,RXOK, TXErr,RXErr,TXBytes,RXBytes);
}
private void raise_connect_status(bool success, String message)
{
if (_event != null) _event.ConnectStatus(success, message);
}
}
}