using CommonLib.LOG; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; namespace CommonLib.DAQ { public class CardADLINK :INotifyPropertyChanged { protected static int AllCardCount; protected int CardNO; /// /// 板卡在系统中的编号 /// private int CardNumberInSystem = -1; /// /// 缓存大小 /// protected const int DATA_COUNT = CardADLINK_Wrapper.MAX_CH_NUM * CardADLINK_Wrapper.DATA_COUNT_PERCH ; /// /// 缓存 /// protected double[] Voltage = new Double[DATA_COUNT]; private Int32[] DataBuffer = new Int32[DATA_COUNT]; private int bufLen = (DATA_COUNT * sizeof(UInt32)); private IntPtr IntPBuffer = IntPtr.Zero; /// /// 单块卡的设置 /// public MCMDAQ_DEVICE mCMDAQ_DEVICE { get; protected set; } = new MCMDAQ_DEVICE(); #region .ctor public CardADLINK() { CardNO = AllCardCount; AllCardCount++; } #endregion #region attrib protected bool m_Enable = false; protected ManualResetEvent EventKill = new ManualResetEvent(false); protected Thread ThreadRead = null; public bool Enable { get { return m_Enable; } set { Boolean bPreEn = m_Enable; if (bPreEn != value) { if (value) { m_Enable = InitDevice(); } else { CloseDevice(); m_Enable = value; } if (bPreEn != m_Enable) OnPropertyChanged(); } } } EventHandler EventError = null; public int m_chlCnt = 0; public int chlCnt { get { return m_chlCnt; } set { if (value != m_chlCnt) { OnPropertyChanged(); } } } private void DoEventError(int errCode,string ErrorInfo) { ErrInfo info = new ErrInfo(errCode, ErrorInfo); EventError?.Invoke(this,info); } /// /// 断开连接 /// private void CloseDevice() { int err = -1; //杀死线程 try { if (ThreadRead != null) { while (ThreadRead.IsAlive) { EventKill.Set(); Thread.Sleep(10); } } } catch (Exception ex) { string Info = $"{ex.Message} \n{ex.StackTrace}"; LogStorage.Logs.Add(LogLevel.Error, Info); DoEventError(err, Info); } finally { Marshal.FreeHGlobal(IntPBuffer); //关闭端口 } } /// /// 连接设备 /// /// private bool InitDevice() { string Info = string.Empty; Boolean bResult = false; int err = -1; ushort CardNumber = 0; IntPBuffer = Marshal.AllocHGlobal(bufLen); try { // 分配内存 // err = CardADLINK_Wrapper.MCM_Release_Card(CardNumber); // 注册板卡,获取板卡ID CardNumberInSystem = CardADLINK_Wrapper.MCM_Register_Card(mCMDAQ_DEVICE.HostName); // 配置板卡通道 if (CardNumberInSystem < 0) { throw (new Exception($"MCM_Register_Card Fail CardNumberInSystem= {CardNumberInSystem}")); } CardNumber = (ushort)CardNumberInSystem; err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferMode(CardNumber, false); if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferMode] err = {0} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } ushort wChanCfg1 = CardADLINK_Wrapper.MCM_AI_DisableIEPE | CardADLINK_Wrapper.MCM_AI_Coupling_DC | CardADLINK_Wrapper.MCM_AI_PseudoDifferential; ushort wChanCfg2 = CardADLINK_Wrapper.MCM_AI_DisableIEPE | CardADLINK_Wrapper.MCM_AI_Coupling_DC | CardADLINK_Wrapper.MCM_AI_PseudoDifferential; ushort wChanCfg3 = CardADLINK_Wrapper.MCM_AI_DisableIEPE | CardADLINK_Wrapper.MCM_AI_Coupling_DC | CardADLINK_Wrapper.MCM_AI_PseudoDifferential; ushort wChanCfg4 = CardADLINK_Wrapper.MCM_AI_DisableIEPE | CardADLINK_Wrapper.MCM_AI_Coupling_DC | CardADLINK_Wrapper.MCM_AI_PseudoDifferential; // 配置板卡通道 // 不使能IEPE,DC耦合方式,伪差分连接 err = CardADLINK_Wrapper.MCM_AI_204_Chan_Config( CardNumber, wChanCfg1, wChanCfg2, wChanCfg3, wChanCfg4 ); if (err != 0) { throw new Exception($"[MCM_AI_204_Chan_Config] err ={err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } // 设置触发参数 // 使用板载时钟,立即触发 ushort wConvSrc = CardADLINK_Wrapper.MCM_AI_CONVSRC_INT; ushort wTrigMode = CardADLINK_Wrapper.MCM_AI_TRGMOD_POST; ushort wTrigCtrl = (ushort)CardADLINK_Wrapper.MCM_Trig_Type.MCM_AI_TRGSRC_SOFT; uint wReTrigCnt = 0; uint dwDLY1Cnt = 0; uint dwDLY2Cnt = 0; double dwTrgLevel = 0; err = CardADLINK_Wrapper.MCM_AI_Trig_Config( CardNumber, wConvSrc, wTrigMode, wTrigCtrl, wReTrigCnt, dwDLY1Cnt, dwDLY2Cnt, dwTrgLevel ); // 使用板载时钟,立即触发 if (err != 0) { throw new Exception($"[MCM_AI_204_Trig_Config] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } // 使能双buffer模式 err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferMode(CardNumber, true); if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferMode] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } // 配置通道数组,选择所有通道 UInt16[] chs = { (UInt16) CardADLINK_Wrapper.AI_CHANNEL.AI_CH_0, (UInt16) CardADLINK_Wrapper.AI_CHANNEL.AI_CH_1, (UInt16) CardADLINK_Wrapper.AI_CHANNEL.AI_CH_2, (UInt16) CardADLINK_Wrapper.AI_CHANNEL.AI_CH_3 }; // 设置每通道输入范围,±10V输入 UInt16[] adranges = { (UInt16) CardADLINK_Wrapper.VRange.AD_B_10_V, (UInt16) CardADLINK_Wrapper.VRange.AD_B_10_V, (UInt16) CardADLINK_Wrapper.VRange. AD_B_10_V, (UInt16) CardADLINK_Wrapper.VRange. AD_B_10_V }; UInt16 asyncMode = (UInt16) CardADLINK_Wrapper.SyncMode.ASYNCH_OP; err = CardADLINK_Wrapper.MCM_AI_ContReadMultiChannels( CardNumber, 4,//CardADLINK_Wrapper.CH_NUM, chs, adranges, IntPBuffer, CardADLINK_Wrapper.DATA_COUNT_PERCH, CardADLINK_Wrapper.SAMPLING_RATE, asyncMode ); if (err != 0) { throw new Exception($"[MCM_AI_ContReadMultiChannels] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } ThreadRead = new Thread(TaskRead); ThreadRead.IsBackground = true; ThreadRead.Start(); bResult = err == 0; } catch (Exception ex) { int err2 = CardADLINK_Wrapper.MCM_Release_Card(CardNumber); // 释放板卡资源 Info = $"{mCMDAQ_DEVICE.HostName} {ex.Message} \n{ex.StackTrace}"; LogStorage.Logs.Add(LogLevel.Error, Info); } finally { if(bResult==false) { CloseDeviceBySelf(CardNumber); } } return bResult; } public EventHandler EventVoltage; public void DoEventVoltage() { EventVoltage?.Invoke(this, new EventArgs()); } private void TaskRead() { ushort CardNumber = (ushort)CardNumberInSystem; int err = -1; byte halfReady = 0; byte stopFlag = 0; UInt16 overrunFlag = 0; EventKill.Reset(); try { while (EventKill.WaitOne(10) == false) { err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferHalfReady(CardNumber, out halfReady, out stopFlag); if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferHalfReady] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } if (halfReady == 1) { err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferTransfer(CardNumber, IntPBuffer); if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferTransfer] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferOverrun(CardNumber, 0, out overrunFlag); if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferOverrun] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } Marshal.Copy(IntPBuffer, DataBuffer, 0, DATA_COUNT); err = CardADLINK_Wrapper.MCM_AI_ContVScale(CardNumber, CardADLINK_Wrapper.VRange.AD_B_10_V, IntPBuffer, Voltage, DATA_COUNT); if (err != 0) { throw new Exception($"[MCM_AI_ContVScale] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } DoEventVoltage(); } } } catch (Exception ex) { int err2 = CardADLINK_Wrapper.MCM_Release_Card(CardNumber); // 释放板卡资源 string Info = $"{mCMDAQ_DEVICE.HostName} {ex.Message} \n{ex.StackTrace}"; LogStorage.Logs.Add(LogLevel.Error, Info); } finally { try { CloseDeviceBySelf(CardNumber); } catch(Exception ex) { string Info = $"{mCMDAQ_DEVICE.HostName} {ex.Message} \n{ex.StackTrace}"; LogStorage.Logs.Add(LogLevel.Error, Info); } } } #endregion void CloseDeviceBySelf(ushort CardNumber) { string Info = string.Empty; UInt32 accessCnt = 0; // 可访问数 int err = 0; try { err = CardADLINK_Wrapper.MCM_AI_AsyncClear(CardNumber, ref accessCnt); // 清除缓存 if (err != 0) { throw new Exception($"[MCM_AI_AsyncClear] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } err = CardADLINK_Wrapper.MCM_AI_AsyncDblBufferMode(CardNumber, false); // 清除双buffer模式 if (err != 0) { throw new Exception($"[MCM_AI_AsyncDblBufferMode] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } err = CardADLINK_Wrapper.MCM_Release_Card(CardNumber); // 释放板卡资源 if (err != 0) { throw new Exception($"[MCM_Release_Card] err = {err} {((CardADLINK_Wrapper.CARDADLINK_ERROR)err).ToString()}"); } } catch (Exception ex) { Info = $"{mCMDAQ_DEVICE.HostName} {ex.Message} \n{ex.StackTrace}"; LogStorage.Logs.Add(LogLevel.Error, Info); } } #region staticMethod /* public static int ScanDevice(Type type) { ushort wModuleNum = 0; MCMDAQ_DEVICE[] _AvailModules = new MCMDAQ_DEVICE[250]; var card = Activator.CreateInstance(type); // DAQCard card = new DAQCard(); //启动DDS模式 ,网页连上 板卡,启用 //网卡配置文件ospl.xml // AUTO 修改为 // MCM204 //然后将网卡名字修改为 MCM204 int err = CardADLINK_Wrapper.MCM_Device_Scan(out wModuleNum, _AvailModules); // 扫描设备 if (err == 0) { dictCard.Clear(); CardADLINK.AllCardCount = 0; for (int i = 0; i < wModuleNum; i++) { card = Activator.CreateInstance(type); //card.mCMDAQ_DEVICE = _AvailModules[i]; //dictCard.Add(card.CardNO, card); ; } } else { if (Debugger.isInDebug()) { MCMDAQ_DEVICE module = new MCMDAQ_DEVICE(); module.IP = "169.254.1.11"; module.cardID = 0; module.HostName ="MCM204-11"; module.MAC = "00:30:64:32:62:b0"; module.deviceID = 204; module.moduleType = 5; //card.mCMDAQ_DEVICE = module; //dictCard.Add(card.CardNO, card); err = 0; } } return err; } */ #endregion #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; /// /// //属性更新事件 CallerMemberName 自动填写属性的名字 /// /// //[CallerMemberName] 需要 4.0以上才有 /// protected virtual void OnPropertyChanged([CallerMemberName] string propertyName=null) { //通过反射读取变量名,将值加入log if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion } }