402 lines
11 KiB
C#
402 lines
11 KiB
C#
using Aurora.Api;
|
|
using Aurora.Api.Devices;
|
|
using Hermes;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AuroraACS
|
|
{
|
|
|
|
public class ACSIO : Device
|
|
{
|
|
private readonly Logger Log = new Logger("ACSDIO");
|
|
|
|
ACSDevice _ACS;
|
|
ACSIOConfig _Config;
|
|
|
|
// For Simulation Buffer
|
|
public int[] BuffDIN { get; set; }
|
|
public int[] BuffDOUT { get; set; }
|
|
|
|
public int[] SimulDIN { get; set; }
|
|
public int[] SimulDOUT { get; set; }
|
|
|
|
#region Buffer Infos. For 3rdParty - BeckHoff
|
|
private string EC_DIN = "EC_DIN";
|
|
private string EC_DOUT = "EC_DOUT";
|
|
private string EC_AIN = "EC_AIN";
|
|
private string EC_AOUT = "EC_AOUT";
|
|
#endregion
|
|
|
|
private object _LockObject = new object();
|
|
private eIOType _Type;
|
|
public int RetryCount = 0;
|
|
|
|
public ACSIO(ACSDevice acs)
|
|
{
|
|
Type = DeviceType.Etc;
|
|
_ACS = acs;
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
|
|
}
|
|
|
|
protected override int DoActivate(IDeviceConfig config)
|
|
{
|
|
_Config = config as ACSIOConfig;
|
|
if (!_ACS.IsActivated) {
|
|
return E1.NETWORK;
|
|
}
|
|
|
|
//[Coverity] CID 12366: (#1 of 1): 데이터 경합 상태 (GUARDED_BY_VIOLATION)
|
|
//2.missing_lock: 락 ACSIO._LockObject을(를) 유지하지 않고 this.RetryCount에 액세스합니다.다른 곳에서, ACSIO.RetryCount은(는) ACSIO._LockObject을(를) 유지한 상태에서 3회 중 2회 작성하였습니다.
|
|
lock (_LockObject) {
|
|
RetryCount = 0;
|
|
}
|
|
|
|
IsSimul = _ACS.IsSimul;
|
|
|
|
_Type = _Config.Type;
|
|
|
|
if (_Type == eIOType.BeckHoff) {
|
|
EC_DIN = _Config.InputIOName;
|
|
EC_DOUT = _Config.OutputIOName;
|
|
}
|
|
|
|
BuffDIN = new int[_Config.IO_INPUT_BOARD_NUM];
|
|
BuffDOUT = new int[_Config.IO_OUTPUT_BOARD_NUM];
|
|
if (IsSimul) {
|
|
SimulDIN = new int[_Config.IO_INPUT_BOARD_NUM];
|
|
SimulDOUT = new int[_Config.IO_OUTPUT_BOARD_NUM];
|
|
RunSimulationTask();
|
|
}
|
|
|
|
RunMonitor();
|
|
|
|
return E1.OK;
|
|
}
|
|
|
|
private void RunSimulationTask()
|
|
{
|
|
Random r = new Random();
|
|
Task.Run(() => {
|
|
while (IsActivated) {
|
|
for (int i = 0; i < _Config.IO_INPUT_BOARD_NUM; i++) {
|
|
var input = i * 100;
|
|
var value = input + r.Next(0, 99);
|
|
SimulDIN[i] = value;
|
|
}
|
|
Thread.Sleep(1000);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void RunMonitor()
|
|
{
|
|
// 실시간 update
|
|
Task.Run(() => {
|
|
|
|
BuffDIN = GetInputAll();
|
|
BuffDOUT = GetOutputAll();
|
|
#if DEBUG
|
|
//Stopwatch sw = new Stopwatch();
|
|
//sw.Start();
|
|
#endif
|
|
|
|
// Update
|
|
while (IsActivated) {
|
|
lock (_LockObject) {
|
|
BuffDIN = GetInputAll();
|
|
if (BuffDIN == null) {
|
|
RetryCount++;
|
|
}
|
|
BuffDOUT = GetOutputAll();
|
|
if (BuffDOUT == null) {
|
|
RetryCount++;
|
|
}
|
|
}
|
|
Thread.Sleep(10);
|
|
}
|
|
});
|
|
}
|
|
|
|
protected override int DoDeactivate()
|
|
{
|
|
return E1.OK;
|
|
}
|
|
|
|
private bool CheckInputRange(int port, int bit = 0)
|
|
{
|
|
if (CheckInputRange(port))
|
|
return false;
|
|
if (CheckBit(bit))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool CheckOutputRange(int port, int bit = 0)
|
|
{
|
|
if (CheckInputRange(port))
|
|
return false;
|
|
if (CheckBit(bit))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool CheckInputRange(int port) => port < 0 || port >= _Config.IO_INPUT_BOARD_NUM;
|
|
private bool CheckOutputRange(int port) => port < 0 || port >= _Config.IO_OUTPUT_BOARD_NUM;
|
|
private bool CheckBit(int bit) => bit < 0 || bit >= _Config.IO_COUNT;
|
|
|
|
#region public methods
|
|
public int GetInputValue(int port, int bit)
|
|
{
|
|
if (!CheckInputRange(port, bit))
|
|
return -1;
|
|
|
|
if (BuffDIN != null) {
|
|
return GetBitValue(bit, BuffDIN[port]);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int GetOutputValue(int port, int bit)
|
|
{
|
|
if (!CheckInputRange(port, bit))
|
|
return -1;
|
|
|
|
if (BuffDIN != null) {
|
|
return GetBitValue(bit, BuffDOUT[port]);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public bool SetOutput(int port, int bit, int value)
|
|
{
|
|
if (CheckOutputRange(port))
|
|
return false;
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
return _ACS.SetOutput(port, bit, value);
|
|
}
|
|
|
|
bool res = false;
|
|
lock (_LockObject) { // int값을 읽어서 업데이트 하는 계념이므로 여기저기서 쓰면 안 된다.
|
|
int val = GetOutputInternal(port, bit, out int totVal);
|
|
if (value == val) {
|
|
return true;
|
|
}
|
|
|
|
totVal ^= GetBitPos(bit);
|
|
res = SetOutputPort(port, totVal);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endregion
|
|
|
|
#region internal methods
|
|
|
|
internal int GetInput(int port, int bit)
|
|
{
|
|
if (!CheckInputRange(port, bit))
|
|
return -1;
|
|
|
|
if (IsSimul) {
|
|
int simulVal = SimulDIN[port];
|
|
return GetBitValue(bit, simulVal);
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
return _ACS.GetInput(port, bit);
|
|
}
|
|
|
|
int val = GetNodeInternal(EC_DIN, port);
|
|
return GetBitValue(bit, val);
|
|
}
|
|
|
|
internal int GetInputPort(int port)
|
|
{
|
|
if (!CheckInputRange(port))
|
|
return -1;
|
|
|
|
if (IsSimul) {
|
|
return SimulDIN[port];
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
return _ACS.GetInputPort(port);
|
|
}
|
|
|
|
return GetNodeInternal(EC_DIN, port);
|
|
}
|
|
|
|
internal int GetOutput(int port, int bit)
|
|
{
|
|
if (!CheckOutputRange(port, bit))
|
|
return -1;
|
|
|
|
if (IsSimul) {
|
|
int simulVal = SimulDOUT[port];
|
|
return GetBitValue(bit, simulVal);
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
return _ACS.GetOutput(port, bit);
|
|
}
|
|
|
|
int val = GetNodeInternal(EC_DOUT, port);
|
|
return GetBitValue(bit, val);
|
|
}
|
|
|
|
internal int GetOutputPort(int port)
|
|
{
|
|
if (!CheckOutputRange(port))
|
|
return -1;
|
|
|
|
if (IsSimul) {
|
|
return SimulDOUT[port];
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
return _ACS.GetOutputPort(port);
|
|
}
|
|
|
|
return GetNodeInternal(EC_DOUT, port);
|
|
}
|
|
|
|
internal int[] GetInputAll()
|
|
{
|
|
if (!IsActivated)
|
|
return null;
|
|
|
|
if (IsSimul) {
|
|
return SimulDIN;
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
int[] ret = new int[_Config.IO_INPUT_BOARD_NUM];
|
|
for (int i = 0; i < _Config.IO_INPUT_BOARD_NUM; i++){
|
|
ret[i] = GetInputPort(i);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (!_ACS.ReadVariableIntArr(EC_DIN, out int[] val))
|
|
return null;
|
|
|
|
return val;
|
|
}
|
|
|
|
internal int[] GetOutputAll()
|
|
{
|
|
if (!IsActivated)
|
|
return null;
|
|
|
|
if (IsSimul) {
|
|
return SimulDOUT;
|
|
}
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
int[] ret = new int[_Config.IO_INPUT_BOARD_NUM];
|
|
for (int i = 0; i < _Config.IO_INPUT_BOARD_NUM; i++) {
|
|
ret[i] = GetOutputPort(i);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (!_ACS.ReadVariableIntArr(EC_DOUT, out int[] val)) {
|
|
return null;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
internal bool SetOutputAll(int[] vals)
|
|
{
|
|
if (!IsActivated)
|
|
return false;
|
|
|
|
if (_Type == eIOType.Internal) {
|
|
for (int i = 0; i < vals.Length; i++) {
|
|
if (!_ACS.SetOutputPort(i, vals[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (!_ACS.WriteVariableIntArr(EC_DOUT, vals))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
#endregion
|
|
|
|
#region BackHoff Only
|
|
private int GetBitValue(int pos, int val) => (val >> pos) & 1;
|
|
private int GetBitPos(int pos, int val = 1) => val << pos;
|
|
|
|
private int GetNodeInternal(string inout, int node)
|
|
{
|
|
if (_ACS.ReadVariableInt(inout, out int val, node))
|
|
return val;
|
|
|
|
return -1;
|
|
}
|
|
|
|
internal int GetOutputInternal(int node, int bit, out int val)
|
|
{
|
|
val = -1;
|
|
if (!CheckOutputRange(node, bit))
|
|
return -1;
|
|
|
|
val = GetNodeInternal(EC_DOUT, node);
|
|
return GetBitValue(bit, val);
|
|
}
|
|
|
|
private bool SetOutputPort(int node, int value)
|
|
{
|
|
if (!IsActivated) {
|
|
return false;
|
|
}
|
|
|
|
if (CheckOutputRange(node)) {
|
|
return false;
|
|
}
|
|
|
|
bool res = false;
|
|
if (IsSimul) {
|
|
BuffDOUT[node] = value;
|
|
res = true;
|
|
} else {
|
|
res = _ACS.WriteVariableInt(EC_DOUT, value, node);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endregion
|
|
|
|
#region AI, EXT
|
|
public double GetAnalogInputNT(int port) => _ACS.GetAnalogInputNT(port);
|
|
public double GetAnalogOutputNT(int port) => _ACS.GetAnalogOutputNT(port);
|
|
public bool SetAnalogOutputNT(int port, double value) => _ACS.SetAnalogOutputNT(port, value);
|
|
public int GetExtInput(int port, int bit) => _ACS.GetExtInput(port, bit);
|
|
public int GetExtInputPort(int port) => _ACS.GetExtInputPort(port);
|
|
public int GetExtOutput(int port, int bit) => _ACS.GetExtOutput(port, bit);
|
|
public int GetExtOutputPort(int port) => _ACS.GetExtOutputPort(port);
|
|
public bool SetExtOutput(int port, int bit, int value) => _ACS.SetExtOutput(port, bit, value);
|
|
public bool SetExtOutputPort(int port, int value) => _ACS.SetExtOutputPort(port, value);
|
|
#endregion
|
|
}
|
|
}
|