232 lines
7.9 KiB
C#
232 lines
7.9 KiB
C#
using Aurora;
|
|
using Aurora.Api;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reactive.Linq;
|
|
using System.Reactive.Subjects;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
|
|
namespace AuroraACS
|
|
{
|
|
class IOMonitor
|
|
{
|
|
private readonly Logger Log = new Logger("IOMonitor");
|
|
private static IOMonitor _instance;
|
|
private IOMonitor()
|
|
{
|
|
_ioInSubject = new Subject<IOItem>();
|
|
_ioOutSubject = new Subject<IOOutItem>();
|
|
BitInputs = DIN.GetAllInfo().ToArray();
|
|
BitOutputs = DOUT.GetAllInfo().ToArray();
|
|
}
|
|
|
|
public static IOMonitor GetInstance()
|
|
{
|
|
if (_instance == null)
|
|
_instance = new IOMonitor();
|
|
|
|
return _instance;
|
|
}
|
|
|
|
private AddrInfo[] BitInputs;
|
|
private AddrInfo[] BitOutputs;
|
|
|
|
private ACSIOEx _dio;
|
|
private IDisposable _ioMonitor;
|
|
private IDisposable _ioOutMonitor;
|
|
private Subject<IOItem> _ioInSubject; // Address, value
|
|
private Subject<IOOutItem> _ioOutSubject; // Address, value
|
|
public IObservable<IOItem> IO_Observable => _ioInSubject.AsObservable();
|
|
public IObservable<IOOutItem> IOOut_Observable => _ioOutSubject.AsObservable();
|
|
|
|
private int[] _prevInputPorts = new int[IOItem.NUM_PORTS];
|
|
private int[] _prevOutputPorts = new int[IOItem.NUM_PORTS];
|
|
private IOItem _ioInItem = new IOItem();
|
|
private IOOutItem _ioOutItem = new IOOutItem();
|
|
|
|
public void Init(ACSIOEx dio)
|
|
{
|
|
_dio = dio;
|
|
|
|
var active = Application.Current.AuroraEnv().EventObservable.AsObservable(AuroraSysEvent.SYS_DEVICE_ACTIVATED);
|
|
var deactive = Application.Current.AuroraEnv().EventObservable.AsObservable(AuroraSysEvent.SYS_DEVICE_DEACTIVATED);
|
|
Observable.Merge(active, deactive)
|
|
.Where(msg => msg.From == dio.DeviceId)
|
|
.Subscribe(msg => DevActivated(msg));
|
|
|
|
_ioMonitor = Observable.Interval(TimeSpan.FromMilliseconds(1))
|
|
.Where(x => _dio.IsActivated)
|
|
.Where(tick => GetIO())
|
|
.Subscribe(_ => { _ioInItem.IsInit = false; _ioInSubject.OnNext(_ioInItem); });
|
|
_ioOutMonitor = Observable.Interval(TimeSpan.FromMilliseconds(1))
|
|
.Where(x => _dio.IsActivated)
|
|
.Where(tick => GetIOOut())
|
|
.Subscribe(_ => { _ioOutItem.IsInit = false; _ioOutSubject.OnNext(_ioOutItem); });
|
|
}
|
|
|
|
private void DevActivated(EventMessage msg)
|
|
{
|
|
if (msg.From == _dio.DeviceId) {
|
|
if (msg.Subject == AuroraSysEvent.SYS_DEVICE_ACTIVATED) {
|
|
Log.D("Init start.");
|
|
_initializing = true;
|
|
if (GetIOAll()) {
|
|
_ioInItem.IsInit = true;
|
|
_ioInSubject.OnNext(_ioInItem);
|
|
_ioOutItem.IsInit = true;
|
|
_ioOutSubject.OnNext(_ioOutItem);
|
|
//System.Threading.Thread.Sleep(50);
|
|
}
|
|
_initializing = false;
|
|
Log.D("Init end.");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool _initializing = false;
|
|
private bool GetIO()
|
|
{
|
|
if (_initializing == true)
|
|
return false;
|
|
|
|
//int k = 0;
|
|
bool changed = false;
|
|
int[] val = _dio.GetInputAll();
|
|
if (val == null)
|
|
return false;
|
|
for (int i = 0; i < IOItem.NUM_PORTS; i++) {
|
|
int nodeAddr = (i << 4);
|
|
CalcIO(ref _prevInputPorts[i], val[i], nodeAddr, _ioInItem.IsChanged, _ioInItem.ChangedVaslues, ref changed, BitInputs);
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
private bool GetIOOut()
|
|
{
|
|
if (_initializing == true)
|
|
return false;
|
|
|
|
//int k = 0;
|
|
bool changed = false;
|
|
int[] outVal = _dio.GetOutputAll();
|
|
if (outVal == null)
|
|
return false;
|
|
for (int i = 0; i < IOItem.NUM_PORTS; i++) {
|
|
int nodeAddr = (i << 4);
|
|
CalcIO(ref _prevOutputPorts[i], outVal[i], nodeAddr, _ioOutItem.IsOutChanged, _ioOutItem.ChangedOutVaslues, ref changed, BitOutputs);
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
private void CalcIO(ref int _prevport, int val, int nodeAddr, bool[] isChanged, byte[] changedVals, ref bool changed, AddrInfo[] addrInfos)
|
|
{
|
|
if (_prevport != val) { // Port보고 다르면... 세부적으로 언 놈 다른지 보고 날리기...
|
|
var diff = _prevport ^ val;
|
|
for (int j = 0; j < 8; j++) {
|
|
int addr = nodeAddr + j;
|
|
isChanged[addr] = false;
|
|
if ((diff & (1 << j)) != 0) { // 참이면
|
|
changed = true;
|
|
isChanged[addr] = true;
|
|
changedVals[addr] = (byte)((val >> j) & 1);
|
|
}
|
|
}
|
|
_prevport = val;
|
|
} else {
|
|
for (int j = 0; j < 8; j++) {
|
|
int addr = nodeAddr + j;
|
|
isChanged[addr] = false;
|
|
}
|
|
_prevport = val;
|
|
}
|
|
|
|
if (changed) {
|
|
UpdateValues(isChanged, changedVals, addrInfos);
|
|
}
|
|
}
|
|
|
|
private unsafe void UpdateValues(bool[] isChanged, byte[] changedVals, AddrInfo[] addrInfos)
|
|
{
|
|
fixed (bool* ptrIsChanged = isChanged)
|
|
fixed (byte* ptrChangedVals = changedVals) {
|
|
for (int i = 0; i < addrInfos.Length; i++) {
|
|
if (isChanged[addrInfos[i].Idx])
|
|
addrInfos[i].Value = changedVals[addrInfos[i].Idx];
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool GetIOAll()
|
|
{
|
|
try {
|
|
_ioInItem.Data = _dio.GetInputAll();
|
|
_ioOutItem.Data = _dio.GetOutputAll();
|
|
if (_ioInItem.Data == null || _ioOutItem.Data == null)
|
|
return false;
|
|
|
|
for (int i = 0; i < IOItem.NUM_PORTS; i++) {
|
|
int nodeAddr = (i << 4);
|
|
for (int j = 0; j < 8; j++) {
|
|
int addr = nodeAddr + j;
|
|
_ioInItem.IsChanged[addr] = true;
|
|
_ioInItem.ChangedVaslues[addr] = (byte)((_ioInItem.Data[i] >> j) & 1);
|
|
|
|
_ioOutItem.IsOutChanged[addr] = true;
|
|
_ioOutItem.ChangedOutVaslues[addr] = (byte)((_ioOutItem.Data[i] >> j) & 1);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} catch (Exception exc) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class IOItem
|
|
{
|
|
private object lockObj = new object();
|
|
public bool IsInit = false;
|
|
public const int NUM_PORTS = 64;
|
|
public byte[] ChangedVaslues = new byte[1040];
|
|
public bool[] IsChanged = new bool[1040];
|
|
private int[] data = new int[NUM_PORTS];
|
|
public int[] Data
|
|
{
|
|
get => data;
|
|
set
|
|
{
|
|
lock (lockObj)
|
|
{
|
|
data = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class IOOutItem
|
|
{
|
|
private object lockObj = new object();
|
|
public bool IsInit = false;
|
|
public const int NUM_PORTS = 64;
|
|
public byte[] ChangedOutVaslues = new byte[1040];
|
|
public bool[] IsOutChanged = new bool[1040];
|
|
|
|
private int[] data = new int[NUM_PORTS];
|
|
public int[] Data {
|
|
get => data;
|
|
set {
|
|
lock (lockObj)
|
|
{
|
|
data = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|