HRESULT CbDevice::EnableSwClocking() { double maxRate, minRate; // // It is possible that the hardware will not have the same capabilities as our software clocking // In this case we must adjust our assumptions as to what the MIN and MAX sampling rates // should be. // // Decide the true maximum sampling rate if(_maxSampleRate < MAX_SW_SAMPLERATE) maxRate = _maxSampleRate; else maxRate = MAX_SW_SAMPLERATE; // Decide the true minimum sampling rate if(_minSampleRate > MIN_SW_SAMPLERATE) minRate = _minSampleRate; else minRate = MIN_SW_SAMPLERATE; RETURN_HRESULT(pSampleRate.SetRange(minRate, maxRate)); // Set the default rate to 1/5 the max rate double defaultRate = int(maxRate/5); pSampleRate.SetDefaultValue(defaultRate); // Range check the existing sample rate if (pSampleRate>maxRate) { pSampleRate=maxRate; } else if (pSampleRate<minRate) { pSampleRate=minRate; } // If this HW only supports SW Clocking then set the sample rate to the default if ( _ClockingType == SOFTWARE ) { pSampleRate = defaultRate; } pSampleRate=RoundRate(pSampleRate); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"minsamplerate", CComVariant(minRate))); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"maxsamplerate", CComVariant(maxRate))); return S_OK; }
HRESULT CbDevice::SetClockSource() { if (_UseSoftwareClock) { return EnableSwClocking(); } else { RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"minsamplerate", CComVariant(_minSampleRate))); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"maxsamplerate", CComVariant(_maxSampleRate))); pSampleRate.SetRange(_minSampleRate,_maxSampleRate); UpdateRateAndSkew(); } return S_OK; }
HRESULT CbDevice::Open(IUnknown *Interface) { RETURN_HRESULT(CmwDevice::Open(Interface)); ATTACH_PROP(SampleRate); return S_OK; //EnableSwClocking(); }
//////////////////////////////////////// // SetProperty() // // Called when a property is changed from the MATLAB environment. // It gives us a chance to update other properties, do error checking, etc. // ///////////////////////////////////// STDMETHODIMP CetfarduinoAin::SetProperty(long User, VARIANT* NewValue) { if (User) { CLocalProp* pProp = PROP_FROMUSER(User); variant_t* val = (variant_t*) NewValue; // SampleRate property if (User == USER_VAL(pSampleRate)) { double newSampleRate = *val; if (pClockSource == CLOCKSOURCE_SOFTWARE) { return CswClockedDevice::SetProperty(User, NewValue); } // Calculate a sample rate which is compatible with the board CalculateSampleRate(newSampleRate); *val = pSampleRate; } // ClockSource property if (User == USER_VAL(pClockSource)) { if ((long)(*val) == CLOCKSOURCE_SOFTWARE) { // Software clocking chosen // First, change the SampleRate to SW clocked defaults double softwareClockedDefault = 100; // Let's avoid magic values pSampleRate.SetDefaultValue(CComVariant(softwareClockedDefault)); pSampleRate = softwareClockedDefault; pSampleRate.SetRange( CComVariant((double)MIN_SW_SAMPLERATE), CComVariant((double)MAX_SW_SAMPLERATE)); EnableSwClocking(); // SamplesPerTrigger needs to be configured so that 1s of input data is acquired pSamplesPerTrigger->put_DefaultValue(CComVariant(softwareClockedDefault)); pSamplesPerTrigger = softwareClockedDefault; } else { // Internal (HW) clocking chosen // First, change the SampleRate to SW clocked defaults double internalClockDefault = 1000; pSampleRate.SetDefaultValue(CComVariant(internalClockDefault)); pSampleRate = internalClockDefault; pSampleRate.SetRange(m_minBoardSampleRate, m_maxBoardSampleRate); // Za SwClocking ovaj dio uradi CswClockedDevice::EnableSwClocking RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"minsamplerate", CComVariant(m_minBoardSampleRate))); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(L"maxsamplerate", CComVariant(m_maxBoardSampleRate))); // SamplesPerTrigger needs to be configured so that 1s of input data is acquired pSamplesPerTrigger->put_DefaultValue(CComVariant(internalClockDefault)); pSamplesPerTrigger = internalClockDefault; } } } return S_OK; }
HRESULT CetfarduinoAin::SetDaqHwInfo() { // ---------------------------------- // Set allowed InputRanges // ---------------------------------- // The SAFEARRAYBOUND is used to create a multi dimensional array SAFEARRAYBOUND rgsabound[2]; //the number of dimensions rgsabound[0].lLbound = 0; rgsabound[0].cElements = _validInputRanges.size(); // bipolar and unipolar - size of dimension 1 rgsabound[1].lLbound = 0; rgsabound[1].cElements = 2; // upper and lower range values - size of dimension 2 SAFEARRAY* ps = SafeArrayCreate(VT_R8, 2, rgsabound); //use the SafeArrayBound to create the array if (ps == NULL) throw "Failure to create SafeArray."; CComVariant vinrange; vinrange.parray = ps; vinrange.vt = VT_ARRAY | VT_R8; double *inRange, *min, *max; HRESULT hr = SafeArrayAccessData(ps, (void**)&inRange); if (FAILED(hr)) { SafeArrayDestroy(ps); throw "Failure to access SafeArray data."; } min = inRange; max = inRange + _validInputRanges.size(); // Iterate through the validRanges, and transfer the Input Ranges. for (RangeList::iterator it = _validInputRanges.begin(); it != _validInputRanges.end(); ++it) { *min++ = it->minVal; *max++ = it->maxVal; } SafeArrayUnaccessData(ps); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"inputranges"), vinrange)); // Polarity // Za sad je predvidjeno samo Unipolarni polaritet... RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"polarity"), CComVariant(L"Unipolar"))); // Description char driverDescrip[] = "Etf Arduino Driver: Analog Input"; RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"vendordriverdescription"), CComVariant(driverDescrip))); return S_OK; }
//////////////////////////////////////////////////////////////////////////////////// // Open() // This routine is called when MatLab executes the 'digitalio' instruction. // Several things should be validated at this point. //////////////////////////////////////////////////////////////////////////////////// HRESULT CadvantechDio::Open(IUnknown *Interface,long ID) { if (ID<0) { return E_INVALID_DEVICE_ID; } RETURN_HRESULT(CmwDevice::Open(Interface)); m_deviceID = static_cast<WORD>(ID); // Set the Device Number to the requested device number set in Matlab. short numDevices; DEVLIST deviceList[MaxDev]; // Structure containing list of installed boards (MaxDev is defined in driver.h) RETURN_ADVANTECH(DRV_DeviceGetList((DEVLIST far *)&deviceList[0], MaxDev, &numDevices)); DWORD index = -1; for (int i=0; i < numDevices; i++) // Find the deviceID which corresponds to the desired board. { if (deviceList[i].dwDeviceNum == m_deviceID) { index = i; } } if (index == -1) { return E_INVALID_DEVICE_ID; } strcpy(m_deviceName, deviceList[index].szDeviceName); // Open device and check that device number is valid RETURN_ADVANTECH(DRV_DeviceOpen(m_deviceID,(LONG far *)&m_driverHandle)); PT_DeviceGetFeatures ptDevFeatures; ptDevFeatures.buffer = (LPDEVFEATURES)&m_devFeatures; ptDevFeatures.size = sizeof(DEVFEATURES); RETURN_ADVANTECH(DRV_DeviceGetFeatures(m_driverHandle, (LPT_DeviceGetFeatures)&ptDevFeatures)); RETURN_HRESULT(LoadINIInfo()); RETURN_HRESULT(SetDaqHwInfo()); return S_OK; } // end of Open()
HRESULT CLabInput::Open(IDaqEngine *engine,int id,DevCaps* DeviceCaps) { RETURN_HRESULT(Cnia2d::Open(engine, id,DeviceCaps)); if (GetDevCaps()->Is700()) { _chanSkewMode->ClearEnumValues(); _chanSkewMode->AddMappedEnumValue(EQUISAMPLE, L"Equisample"); _chanSkewMode=EQUISAMPLE; _chanSkewMode->put_DefaultValue(CComVariant(EQUISAMPLE)); UpdateTimeing(FORSET); } return S_OK; }
HRESULT CbDevice::UpdateChans(bool ForStart) { _chanList.resize(_nChannels); _chanRange.resize(_nChannels); AICHANNEL *aichan=NULL; if (_updateChildren && ForStart) { #ifdef _DEBUG long chancheck=0; _EngineChannelList->GetNumberOfChannels(&chancheck); _ASSERTE(chancheck==_nChannels); #endif for (int i=0; i<_nChannels; i++) { _EngineChannelList->GetChannelStructLocal(i, (NESTABLEPROP**)&aichan); _ASSERTE(aichan); _chanList[i]=static_cast<short>(aichan->Nestable.HwChan); RANGE_INFO *NewInfo; RETURN_HRESULT(FindRange(static_cast<float>(aichan->VoltRange[0]), static_cast<float>(aichan->VoltRange[1]),NewInfo)); _chanRange[i]=NewInfo->rangeInt; if (aichan->Nestable.Type==NPAOCHANNEL) { RETURN_HRESULT(UpdateDefaultChannelValue(i,((AOCHANNEL*)aichan)->DefaultValue)); } } _updateChildren=false; } else { // we still need working chanlist and rangelist if no gainlist } return S_OK; }
//////////////////////////////////////////////////////////////////////////////// // SetChannelProperty() // // Called by the engine when a channel property is set // An interface to the property, the new value and as a link to the channel are passed // to the method //////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CetfarduinoAin::SetChannelProperty(long UserVal, tagNESTABLEPROP* pChan, VARIANT* NewValue) { int Index = pChan->Index-1; // we use 0 based index variant_t& vtNewValue = reinterpret_cast<variant_t&>(*NewValue); // Input Range property if(UserVal == USER_INPUTRANGE) { TSafeArrayAccess<double> NewRange(NewValue); Range* range = 0; RETURN_HRESULT(FindRange(NewRange[0], NewRange[1], range)); NewRange[0] = range->minVal; NewRange[1] = range->maxVal; _updateChildren = true; } _updateChildren = true; return S_OK; }
///////////////////////////////////////////////////////////////////////////// // AdaptorInfo() // // The function is used to elicit relevant info about the current HW.. //..configuration from the HW API. // The info to extract is: //..1)number of boards installed //..2)board names //..3)supported subsystems (AnalogInput, AnalogOutput, DigitalIO) // The function is called by the engine in response to the ML user.. //..command DAQHWINFO ///////////////////////////////////////////////////////////////////////////// HRESULT Cadvantechadapt::AdaptorInfo(IPropContainer * Container) { LONG lDriverHandle = (LONG)NULL; // driver handle PT_DeviceGetFeatures ptDevFeatures; // Devfeatures table DEVFEATURES DevFeatures; // structure for device features int i = 0; // Index variable // Get the name of the adaptor module TCHAR name[256]; GetModuleFileName(_Module.GetModuleInstance(),name,256); // null returns MATLAB version (non existant) RETURN_HRESULT(Container->put_MemberValue(L"adaptordllname",CComVariant(name))); // Place the adaptor name in the appropriate struct in the engine. RETURN_HRESULT(Container->put_MemberValue(L"adaptorname",variant_t(ConstructorName))); // Find board IDs // Start by obtaining the DeviceList. Not stored. short numDevices; // Number of devices DEVLIST deviceList[MaxDev]; // Space to store device information. CComVariant var; // General CComVariant to return info to adaptor engine. RETURN_ADVANTECH(DRV_DeviceGetList((DEVLIST far *)&deviceList[0], MaxDev, &numDevices)); // Create storage for board IDs, bord names and constructors. TSafeArrayVector<CComBSTR> IDs; // Create A SafeArrayVector to store the IDs in IDs.Allocate(numDevices); // Allocate the memory for the number of devices TSafeArrayVector<CComBSTR> Names; // Create A SafeArrayVector to store the Names in Names.Allocate(numDevices); // Allocate the memory for the number of devices SAFEARRAY *ps; // SafeArray for the subsystem support [nDx3 CComBStrs] CComBSTR *subsystems; SAFEARRAYBOUND arrayBounds[2]; arrayBounds[0].lLbound = 0; arrayBounds[0].cElements = numDevices; arrayBounds[1].lLbound = 0; arrayBounds[1].cElements = 3; // AnalogInput, AnalogOutput, DigitalIO subsystems. ps = SafeArrayCreate(VT_BSTR, 2, arrayBounds); if (ps==NULL) return E_FAIL; // Set up the variant to contain subsystem constructor SafeArray var.parray = ps; var.vt = VT_ARRAY | VT_BSTR; HRESULT hRes = SafeArrayAccessData(ps, (void **)&subsystems); if (FAILED (hRes)) { SafeArrayDestroy (ps); return hRes; } // Now loop through each device, getting the ID, BoardName and subsystem support. wchar_t str[40]; for (i=0; i < numDevices; i++) { // Allocate the ID char* string; string = new char[20]; _ltoa(deviceList[i].dwDeviceNum, string, 10); IDs[i] = CComBSTR(string); // Open Device RETURN_ADVANTECH(DRV_DeviceOpen(deviceList[i].dwDeviceNum,(LONG far *)&lDriverHandle)); // Get BoardNames info Names[i] = CComBSTR(deviceList[i].szDeviceName); // Check to see which subsystems the current board supports. // Get device features ptDevFeatures.buffer = (LPDEVFEATURES)&DevFeatures; ptDevFeatures.size = sizeof(DEVFEATURES); RETURN_ADVANTECH(DRV_DeviceGetFeatures(lDriverHandle, (LPT_DeviceGetFeatures)&ptDevFeatures)); if ((DevFeatures.usMaxAIDiffChl + DevFeatures.usMaxAISiglChl) > 0) { swprintf(str, L"analoginput('%s',%s)", (wchar_t*)ConstructorName, (wchar_t*)IDs[i]); subsystems[i]=str; } if (DevFeatures.usMaxAOChl > 0) { swprintf(str, L"analogoutput('%s',%s)", (wchar_t*)ConstructorName, (wchar_t*)IDs[i]); subsystems[i + numDevices]=str; } if ((DevFeatures.usMaxDIChl + DevFeatures.usMaxDOChl) > 0) { swprintf(str, L"digitalio('%s',%s)",(wchar_t*) ConstructorName, (wchar_t*)IDs[i]); subsystems[i + 2*numDevices] = str; } // Close device RETURN_ADVANTECH(DRV_DeviceClose((LONG far *)&lDriverHandle)); } // Return Object Constructor Names since they're in var already. SafeArrayUnaccessData (ps); RETURN_HRESULT(Container->put_MemberValue(L"objectconstructorname",var)); // Return the board names var.Clear(); // resuse the same 'var' variable for the boardnames. Names.Detach(&var); RETURN_HRESULT(Container->put_MemberValue(L"boardnames",var)); // Return the board numbers var.Clear(); //reuse the same 'var' variable for the IDs[] IDs.Detach(&var); RETURN_HRESULT(Container->put_MemberValue(L"installedboardids",var)); return S_OK; } // end of AdaptorInfo()
STDMETHODIMP SoundDA::SetProperty(long User, VARIANT *NewValue) // return false for fail { if (User) { variant_t *var = (variant_t*)NewValue; // // special case: if bitsPerSample is being changed, we // need to update the daqHwInfo to reflect this // if (User==(long)&_bitsPerSample) { // set the daqHwInfo value which depends on the BitsPerSample property double offset; // set the data type to match the bits, default is Int16 long datatype; long bits=(long)*var; switch (bits) { case 8: datatype=VT_UI1; offset=128; break; case 16: datatype=VT_I2; offset=0; break; case 24: datatype=VT_I4; offset=0; break; case 32: datatype=VT_I4; offset=0; break; default: if (bits<16 || bits > 32) return E_INV_BPS; _engine->WarningMessage(L"The bits value that has been set has no standard implementation" L" by sound cards. Acquisition may be unreliable. To remove this warning rebuild the winsound adaptor"); datatype=VT_I4; offset=0; } WaveFormat.SetBits(static_cast<WORD>(bits)); HRESULT hRes = GetHwInfo()->put_MemberValue(L"nativedatatype",CComVariant(datatype)); if (!(SUCCEEDED(hRes))) return hRes; hRes = GetHwInfo()->put_MemberValue(L"bits",*NewValue); if (!(SUCCEEDED(hRes))) return hRes; // now set the offset value that the engin uses to calculate naiveoffset for (int i=0;i<_nChannels;i++) { AOCHANNEL *chan; _EngineChannelList->GetChannelStructLocal(i,(NESTABLEPROP**)&chan); chan->ConversionOffset=offset; } // set the default offset CComPtr<IPropRoot> iProp; GetChannelProperty(L"conversionoffset",&iProp); iProp->put_DefaultValue(CComVariant(offset)); } else if (User==(long)&_standardSampleRates) { // Get a pointer to the IProp interface for theSampleRate property. if ((bool)(*var) == true){ // Need to snap current SampleRate to one of the standard samplerates. // A one percent tolerance is given. // Ex. 8080 snaps to 8000 not 11025. _cSamplesPerSec=SnapSampleRates(_cSamplesPerSec); WaveFormat.SetRate(_cSamplesPerSec); RETURN_HRESULT(SetSampleRateRange(8000,static_cast<long>(WaveCaps.GetMaxSampleRate()))); }else{ // SampleRate can be set to a maximum of 96000Hz. RETURN_HRESULT(SetSampleRateRange(5000,96000)); } } else if (User==(long)&_cSamplesPerSec) { // SampleRate has been chosen. Depending on standardSampleRates value // may need to snap to specified SampleRate to 8000, 11025, 22050, 44100, // A one percent tolerance is given. // Get a pointer to the IProp interface for the StandardSampleRates // property. IProp* iProp; HRESULT hRes = GetProperty(L"StandardSampleRates", &iProp); if (FAILED(hRes)) return hRes; // Get the value of the StandardSampleRates property. variant_t standardSR; iProp->get_Value(&standardSR); switch ((bool)standardSR) { case false: { // StandardSampleRates is off. Don't need to snap but do need to // round up to the next integer value. // Get the fraction portion of the SampleRate (8050.50) double n; double fraction=modf(*var, &n); // If not a fraction round up. if (fraction!=0.0){ *var=(long)++n; } break; } case true: { // StandardSampleRates is on. Need to snap the specified SampleRate to // either 8000, 11025, 22050, 44100 *var = SnapSampleRates(*var); break; } } // close switch iProp->Release(); } //close else // set the local value ((CLocalProp*)User)->SetLocal(*var); } return S_OK; }
///////////////////////////////////////////////////////////////////////////// // Open() // // Function is called by the OpenDevice(), which is in turn called by the engine. // CetfarduinoAin::Open() function's main goals are .. // 1)to initialize the hardware and hardware dependent properties.. // 2)to expose pointers to the engine and the adaptor to each other.. // 3)to process the device ID, which is input by a user in the MATLAB command line. // The call to this function goes through the hierarchical chain: .. //..CetfarduinoAin::Open() -> CswClockedDevice::Open() -> CmwDevice::Open() // CmwDevice::Open() in its turn populates the pointer to the.. //..engine (CmwDevice::_engine), which allows to access all engine interfaces. // Function MUST BE MODIFIED by the adaptor programmer. ////////////////////////////////////////////////////////////////////////////// HRESULT CetfarduinoAin::Open(IUnknown* Interface, long ID) { if (ID < 0) { // Undocumented MATLAB Daq Engine bug! // When Open() returns an error, the reference to the analoginput object is leaked // and never freed! Thereby, all resources this object owns are also leaked since // the destructor is never called. // :TODO: Implement a way to free all resources without the dtor (cannot use RAII for // this object) return CComCoClass<ImwDevice>::Error(CComBSTR("etfarduino: Invalid device ID.")); } RETURN_HRESULT(TBaseObj::Open(Interface)); DeviceId = ID; TCHAR portName[10]; bool registered = service.CheckDeviceRegistered(DeviceId, portName); if (!registered) { char tempMessage[255]; sprintf(tempMessage, "etfarduino: Device %d not found.", DeviceId); return CComCoClass<ImwDevice>::Error(CComBSTR(tempMessage)); } wchar_t idStr[8]; swprintf(idStr, L"%d", ID); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"id"), CComVariant(idStr))); // Fixed device config values. They could be moved to a config file. m_minBoardSampleRate = 4; m_maxBoardSampleRate = 12500; // 80us period _engine->GetBufferingConfig(&m_engineBufferSamples, NULL); // ------------ // SetDaqHwInfo // ------------ wchar_t deviceName[30]; swprintf(deviceName, _T("etfarduino (Device %d)"), DeviceId); RETURN_HRESULT(InitHwInfo( VT_UI2, Bits, MAX_CHANNELS, // maximum number of channels SE_INPUT, // Setting Single Ended input channels Cetfarduinoadapt::ConstructorName, deviceName)); RETURN_HRESULT(SetDaqHwInfo()); //////////////////////////////// Properties /////////////////////////////////// // The following Section sets the Propinfo for the Analog input device // /////////////////////////////////////////////////////////////////////////////// // Attach to the ClockSource property ATTACH_PROP(ClockSource); // The etfarduino must work as both software and internally clocked EnableSwClocking(); pClockSource->AddMappedEnumValue(CLOCKSOURCE_SOFTWARE, TEXT("Software")); pClockSource->AddMappedEnumValue(CLOCKSOURCE_INTERNAL, TEXT("Internal")); pClockSource->put_DefaultValue(CComVariant(CLOCKSOURCE_INTERNAL)); pClockSource = CLOCKSOURCE_INTERNAL; // SampleRate property double defaultSampleRate = 1000; ATTACH_PROP(SampleRate); pSampleRate.SetDefaultValue(CComVariant(defaultSampleRate)); pSampleRate = defaultSampleRate; pSampleRate.SetRange(m_minBoardSampleRate, m_maxBoardSampleRate); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(TEXT("minsamplerate"), CComVariant(m_minBoardSampleRate))); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(TEXT("maxsamplerate"), CComVariant(m_maxBoardSampleRate))); // SamplesPerTrigger property // Needs to be set so that 1s of data is acquired with the default sample rate ATTACH_PROP(SamplesPerTrigger); pSamplesPerTrigger->put_DefaultValue(CComVariant(defaultSampleRate)); pSamplesPerTrigger = defaultSampleRate; // TriggerRepeat property // How many times will the trigger be repeated ATTACH_PROP(TriggerRepeat); // ---------------------------- // Postaviti InputRange default // ---------------------------- CRemoteProp remoteProp; CComVariant var; // Hardcoded input range of [0, 5] [V] double InputRange[2] = {0., 5.}; CreateSafeVector(InputRange, 2, &var); remoteProp.Attach(_EngineChannelList, TEXT("inputrange")); remoteProp->put_DefaultValue(var); remoteProp->put_User(USER_INPUTRANGE); remoteProp.SetRange(InputRange[0], InputRange[1]); remoteProp.Release(); TRemoteProp<long> pInputType; pInputType.Attach(_EnginePropRoot, L"InputType"); pInputType->AddMappedEnumValue(0, L"SingleEnded"); // TODO: May need to add the ChannelSkewMode enumerated property... return S_OK; } // end of Open()
//////////////////////////////////////////////////////////////////////////////////// // SetDaqHWInfo() // Set the fields needed for DaqHwInfo. // It is used when you call daqhwinfo(analoginput('advantech')) //////////////////////////////////////////////////////////////////////////////////// HRESULT CadvantechDio::SetDaqHwInfo() { // Adaptor Name RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"adaptorname"), CComVariant(Cadvantechadapt::ConstructorName))); // Device Name char tempstr[15] = ""; sprintf(tempstr, " (Device %d)", m_deviceID); strcat(m_deviceName, tempstr); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"devicename"), CComVariant(m_deviceName))); // Device ID wchar_t idStr2[10]; swprintf(idStr2, L"%d", m_deviceID ); // Convert the Device id to a string RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"id"), CComVariant(idStr2))); // Vendor Driver Description char vendorDriverDescription[30]; // The place to store the driver description // This call gets the value which corresponds to the description, and converts it to a string strcpy(vendorDriverDescription, m_devFeatures.szDriverName); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"vendordriverdescription"),CComVariant(vendorDriverDescription))); // Vendor Driver Version char vendorDriverVersion[30]; // The place to store the driver description // This call gets the value which corresponds to the description, and converts it to a string strcpy(vendorDriverVersion, m_devFeatures.szDriverVer); RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"vendordriverversion"),CComVariant(vendorDriverVersion))); // Sort out the daqhwinfo for the ports // This calculates the total number of lines that we have available. We do this first so we know how many // different ports we have in total. // NOTE: Advantech hardware has either all configurable lines, or no configurable lines! if (m_configLines > 0) { RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"totallines"), CComVariant(m_configLines))); } else { RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"totallines"), CComVariant((m_inputLines + m_outputLines)))); } // Set the rest of the port info CComVariant var; // Here we create the SafeArray we are going to use to set all port values. SAFEARRAY *ps = SafeArrayCreateVector(VT_I4, 0, m_ports ); if (ps==NULL) { return E_FAIL; } // set the data type and values V_VT(&var)=VT_ARRAY | VT_I4; V_ARRAY(&var)=ps; TSafeArrayAccess <long> ar(&var); // used to access the array // These hold the number of ports supported by the device... m_numInPorts = 0; int numOutPorts = 0; int numConfPorts = 0; // NOTE: The line IDs are returned as 0 -> 7 for port1 and 0 -> 7 for port2. For the 1710 and 818 // port2 corresponds to the hi byte ie. lines 8 -> 15. // PortMasks defined in advantechUtil.h int position = 0; if ((m_inputLines + m_outputLines)/m_ports == 8 || m_configLines/m_ports == 8) // If ports are 8 lines wide... { m_numInPorts = m_inputLines/8; numOutPorts = m_outputLines/8; numConfPorts = m_configLines/8; // Set up PortLineMasks here int numPorts = max((m_numInPorts + numOutPorts) ,m_configLines/8); //for (int i=0; i < (m_numInPorts + numOutPorts); i++) for (int i=0; i < (numPorts); i++) { ar[position] = portMask8; position++; } } else if ((m_inputLines + m_outputLines)/m_ports == 16) // This for PCL730, has ports 16 lines wide { m_numInPorts = m_inputLines/16; numOutPorts = m_outputLines/16; // Set up PortLineMasks here for (int i=0; i < (m_numInPorts + numOutPorts); i++) { ar[position] = portMask16; position++; } } else if (m_inputLines/m_ports == 5) // This for PCL833, has one port of 5 lines { m_numInPorts = 1; // Set up PortLineMasks here ar[0] = portMask5; } else // Else its a PCL735, has one port of 8 lines and another of 4 lines { numOutPorts = 2; // Set up PortLineMasks here ar[0] = portMask8; ar[1] = portMask4; } RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"portlinemasks"),var) ); // Port Directions // NOTE: Advantech names their ports as follows: // // Input Ports: 0 1 2 3... // Output Ports: 0 1 2 3... // // Here we give the Port IDs as follows (to conform to Mathworks): // // Input Ports: 0 1 // Output Ports: 2 3 // or // Configurable Ports: 0 1 2 3 4... position = 0; for (int i = 0; i < m_numInPorts; i++) // First check the input ports. { ar[position] = 0; position++; } for (i = 0; i < numOutPorts; i++) { ar[position] = 1; position++; } for (i = 0; i < numConfPorts; i++) { ar[position] = 2; position++; } RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"portdirections"),var)); // Port IDs for (i = 0; i < m_ports; i++) ar[i] = i; RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"portids"),var)); // PortLineConfig 0:port 1: line // All will be 0 as advantech only supports port configurations... for (i = 0; i < m_ports; i++) ar[i] = 0; RETURN_HRESULT(_DaqHwInfo->put_MemberValue(CComBSTR(L"portlineconfig"),var)); // If the device has configurable ports then we must set the port direction // to "in" for all the ports as this is the default the engine expects. if (numConfPorts > 0) { for (i = 0; i < m_ports; i++) { SetPortDirection(i, 0); } } return S_OK; } // end of SetDaqHwInfo()