// DAQTestingDlg.cpp : implementation file // #include "stdafx.h" #include "DAQTesting.h" #include "DAQTestingDlg.h" #include "NiMath.h" #include ".\daqtestingdlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif void LoadStringVectorInComboBox(CComboBox& comboBox, const CNiStringVector& strings) { for (unsigned long i = 0; i < strings.GetSize(); ++i) comboBox.AddString(strings[i]); } // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CDAQTestingDlg dialog CDAQTestingDlg::CDAQTestingDlg(CWnd* pParent /*=NULL*/) : CDialog(CDAQTestingDlg::IDD, pParent) , m_szFrequency(_T("10.0")) , m_szRate(_T("1000.0")) , m_szSamples(_T("1000")) , m_szAmplitude(_T("1.0")) , m_szDelay(_T("0")) , m_szInputMax1(_T("10.0")) , m_szInputMin1(_T("-10.0")) , m_szInputMax2(_T("10.0")) , m_szInputMin2(_T("-10.0")) , m_szOutputMax1(_T("10.0")) , m_szOutputMin1(_T("-10.0")) , m_szOutputMax2(_T("10.0")) , m_szOutputMin2(_T("-10.0")) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CDAQTestingDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_INPUT1_COMBO, m_input[0]); DDX_Control(pDX, IDC_INPUT2_COMBO, m_input[1]); DDX_Control(pDX, IDC_OUTPUT1_COMBO, m_output[0]); DDX_Control(pDX, IDC_OUTPUT2_COMBO, m_output[1]); DDX_Control(pDX, IDC_EDGE_COMBO, m_edge); DDX_Control(pDX, IDC_START_BUTTON, m_start); DDX_Control(pDX, IDC_STOP_BUTTON, m_stop); DDX_Control(pDX, IDC_INPUT_CWGRAPH, m_inputGraph); DDX_Text(pDX, IDC_FREQ, m_szFrequency); DDX_Text(pDX, IDC_RATE, m_szRate); DDX_Text(pDX, IDC_SAMPLES, m_szSamples); DDX_Text(pDX, IDC_AMPLITUDE, m_szAmplitude); DDX_Text(pDX, IDC_DELAY, m_szDelay); DDX_Text(pDX, IDC_INPUTMAX1, m_szInputMax1); DDX_Text(pDX, IDC_INPUTMIN1, m_szInputMin1); DDX_Text(pDX, IDC_INPUTMAX2, m_szInputMax2); DDX_Text(pDX, IDC_INPUTMIN2,m_szInputMax2); DDX_Text(pDX, IDC_OUTPUTMAX1, m_szOutputMax1); DDX_Text(pDX, IDC_OUTPUTMIN1, m_szOutputMin1); DDX_Text(pDX, IDC_OUTPUTMAX2, m_szOutputMax2); DDX_Text(pDX, IDC_OUTPUTMIN2, m_szOutputMin2); DDX_Control(pDX, IDC_WAVETYPE, m_waveType); } BEGIN_MESSAGE_MAP(CDAQTestingDlg, CDialog) //{{ AFX_MSG_MAP ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_START_BUTTON, OnBnClickedStartButton) ON_BN_CLICKED(IDC_STOP_BUTTON, OnBnClickedStopButton) ON_CBN_SELCHANGE(IDC_INPUT1_COMBO, OnCbnSelchangeInput1Combo) ON_CBN_SELCHANGE(IDC_OUTPUT1_COMBO, OnCbnSelchangeOutput1Combo) END_MESSAGE_MAP() // CDAQTestingDlg message handlers BOOL CDAQTestingDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here // Initialize UI LoadStringVectorInComboBox(m_input[0], CNiDAQmxSystem::GetPhysicalChannels(DAQmxPhysicalChannelTypeAI, DAQmxPhysicalChannelAccessExternal)); LoadStringVectorInComboBox(m_input[1], CNiDAQmxSystem::GetPhysicalChannels(DAQmxPhysicalChannelTypeAI, DAQmxPhysicalChannelAccessExternal)); LoadStringVectorInComboBox(m_output[0], CNiDAQmxSystem::GetPhysicalChannels(DAQmxPhysicalChannelTypeAO, DAQmxPhysicalChannelAccessExternal)); LoadStringVectorInComboBox(m_output[1], CNiDAQmxSystem::GetPhysicalChannels(DAQmxPhysicalChannelTypeAO, DAQmxPhysicalChannelAccessExternal)); m_input[0].SetWindowText("Dev1/ai0"); m_output[0].SetWindowText("Dev1/ao0"); m_input[1].SetWindowText("Dev1/ai0"); m_output[1].SetWindowText("Dev1/ao0"); m_waveType.AddString("Sine"); m_waveType.SetCurSel(0); m_edge.AddString("Rising"); m_edge.AddString("Falling"); m_edge.SetCurSel(0); m_taskRunning = false; return TRUE; // return TRUE unless you set the focus to a control } void CDAQTestingDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CDAQTestingDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this function to obtain the cursor to display while the user drags // the minimized window. HCURSOR CDAQTestingDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } void CDAQTestingDlg::OnBnClickedStartButton() { // TODO: Add your control notification handler code here double imin, imax, omin, omax; double rate, frequency; unsigned int samples; double amplitude; CString input[INPUT]; CNiString output[OUTPUT]; CNiString trigger; CString deviceName[TASK]; CString terminalNameBase[TASK]; CNiReal64Vector outVector[TASK]; CleanUpIfNecessary(); UpdateData(true); m_inputGraph.ClearData(); m_input[0].GetWindowText(input[0]); CNiString(m_szInputMin1) >> imin; CNiString(m_szInputMax1) >> imax; m_input[1].GetWindowText(input[1]); CNiString(m_szInputMin2) >> imin; CNiString(m_szInputMax2) >> imax; int input1 = m_input[0].GetCurSel(); int input2 = m_input[1].GetCurSel(); if (input1 == input2) { AfxMessageBox(_T("Please select a different input channel."), MB_ICONINFORMATION); } m_output[0].GetWindowText(output[0]); CNiString(m_szOutputMin1) >> omin; CNiString(m_szOutputMax1) >> omax; m_output[1].GetWindowText(output[1]); CNiString(m_szOutputMin2) >> omin; CNiString(m_szOutputMax2) >> omax; int output1 = m_output[0].GetCurSel(); int output2 = m_output[1].GetCurSel(); if (output1 == output2) { AfxMessageBox(_T("Please select a different output channel."), MB_ICONINFORMATION); } CNiString(m_szRate) >> rate; CNiString(m_szFrequency) >> frequency; CNiString(m_szSamples) >> samples; CNiString(m_szAmplitude) >> amplitude; DAQmxDigitalEdgeStartTriggerEdge triggerEdge; if (m_edge.GetCurSel() == 0) triggerEdge = DAQmxDigitalEdgeStartTriggerEdgeRising; else triggerEdge = DAQmxDigitalEdgeStartTriggerEdgeFalling; m_inputGraph.ClearData(); m_inputGraph.Axes.Item(1).Minimum = 0; // Don't create a task if already running if (!m_taskRunning) { try { // Create tasks m_inputTask[0] = std::auto_ptr(new CNiDAQmxTask("inputTask1")); m_outputTask[0] = std::auto_ptr(new CNiDAQmxTask("outputTask1")); m_inputTask[1] = std::auto_ptr(new CNiDAQmxTask("inputTask2")); m_outputTask[1] = std::auto_ptr(new CNiDAQmxTask("outputTask2")); for (int i = 0; i < TASK; i++) { // Create channels m_inputTask[i]->AIChannels.CreateVoltageChannel(input[i], "", DAQmxAITerminalConfigurationDifferential, imin, imax, DAQmxAIVoltageUnitsVolts); m_outputTask[i]->AOChannels.CreateVoltageChannel(output[i], "", omin, omax, DAQmxAOVoltageUnitsVolts); // Configure timing m_inputTask[i]->Timing.ConfigureSampleClock("", rate, DAQmxSampleClockActiveEdgeRising, DAQmxSampleQuantityModeContinuousSamples, samples); m_outputTask[i]->Timing.ConfigureSampleClock("", rate, DAQmxSampleClockActiveEdgeRising, DAQmxSampleQuantityModeContinuousSamples, samples); // Set up the start triggers int curpos = 0; deviceName[i] = input[i].Tokenize("/", curpos); terminalNameBase[i]= "/" + GetDeviceName(deviceName[i]) + "/"; m_outputTask[i]->Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(terminalNameBase[i] + "ai/StartTrigger", triggerEdge); // Verify the tasks m_inputTask[i]->Control(DAQmxTaskVerify); m_outputTask[i]->Control(DAQmxTaskVerify); // Write data outVector[i] = CNiReal64Vector(samples); double phase = 0; double cycles = frequency / rate; switch (m_waveType.GetCurSel()) { case 0: default: CNiMath::SineWave(outVector[i], samples, phase, amplitude, cycles); break; } m_writer[i] = std::auto_ptr(new CNiDAQmxAnalogSingleChannelWriter(m_outputTask[i]->Stream)); m_writer[i]->WriteMultiSample(false, outVector[i]); // Start running the task (slaves first) m_outputTask[i]->Start(); m_inputTask[i]->Start(); m_taskRunning = true; m_start.EnableWindow(false); m_stop.EnableWindow(true); // Create the analog input readers m_reader[i] = std::auto_ptr(new CNiDAQmxAnalogSingleChannelReader(m_inputTask[i]->Stream)); m_reader[i]->InstallEventHandler(*this, &CDAQTestingDlg::ReadData); m_reader[i]->ReadMultiSampleAsync(samples, m_data, NULL); } //end of for loop }//end of try loop catch(CException* e) { e->ReportError(); e->Delete(); m_start.EnableWindow(TRUE); m_stop.EnableWindow(FALSE); m_taskRunning = false; }//end of catch loop } } void CDAQTestingDlg::RemoveEventHandler() { for (int i = 0; i < TASK; i++) { if (m_reader[i].get()) { m_taskRunning = false; // Remove our event handler while(!m_reader[i]->RemoveAllEventHandlers()) { ::Sleep(100); MSG msg; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } } void CDAQTestingDlg::CleanUpIfNecessary() { for (int i = 0; i < TASK; i++) { delete m_reader[i].release(); delete m_writer[i].release(); delete m_outputTask[i].release(); delete m_inputTask[i].release(); } } void CDAQTestingDlg::OnBnClickedStopButton() { // TODO: Add your control notification handler code here m_taskRunning = false; m_start.EnableWindow(false); m_stop.EnableWindow(false); RemoveEventHandler(); for (int i = 0; i < TASK; i++) { if (m_inputTask[i].get() != NULL) { m_inputTask[i]->Stop(); } if (m_outputTask[i].get() != NULL) { m_outputTask[i]->Stop(); } } CleanUpIfNecessary(); m_start.EnableWindow(TRUE); } void CDAQTestingDlg::ReadData(CNiDAQmxAsyncOperation asyncHandle, void* userData) { // Handle acquired data event CNiComInitialize com(CNiComInitialize::Apartment); try { // Watch for exceptions asyncHandle.CheckForAsyncException(); // Graph data m_inputGraph.ChartY(m_data, 1.0 / atol(m_szRate)); // Read more data if (m_taskRunning) { for (int i = 0; i < TASK; i++) { m_reader[i]->ReadMultiSampleAsync(atol(m_szSamples), m_data, NULL); } } } catch (CException* e) { e->ReportError(); e->Delete(); m_start.EnableWindow(TRUE); m_stop.EnableWindow(FALSE); m_taskRunning = false; } } CString CDAQTestingDlg::GetDeviceName(CString deviceName) { CNiDAQmxDevice device = CNiDAQmxSystem::LoadDevice(deviceName); if (device.BusType != DAQmxDeviceBusTypeCompactDaq) return deviceName; else return device.CompactDaqChassisDeviceName; } void CDAQTestingDlg::OnCancel() { ShowWindow(SW_HIDE); RemoveEventHandler(); for (int i = 0; i < TASK; i++) { if (m_inputTask[i].get() != NULL) { m_inputTask[i]->Control(DAQmxTaskAbort); } if (m_outputTask[i].get() != NULL) { m_outputTask[i]->Control(DAQmxTaskAbort); } } CleanUpIfNecessary(); CDialog::OnCancel(); } void CDAQTestingDlg::OnCbnSelchangeInput1Combo() { // TODO: Add your control notification handler code here } void CDAQTestingDlg::OnCbnSelchangeOutput1Combo() { // TODO: Add your control notification handler code here }