362 lines
12 KiB
C#
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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|