Add project files.
This commit is contained in:
361
VX3K.cs
Normal file
361
VX3K.cs
Normal file
@@ -0,0 +1,361 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user