Main Page | Modules | Class Hierarchy | Class List | File List | Class Members

di194.cpp

00001 /***************************************************************************
00002                           di194.cpp  -  Linux driver for DI-194 series
00003                                         acquisition device manufactured by
00004                                         DATAQ Instruments, Inc.
00005                              -------------------
00006     begin                : Mon Jun 7 2004
00007     author               : Ioan S. Popescu
00008 
00009 Copyright (C) 2004 DATAQ Instruments, Inc. <develop@dataq.com>
00010 
00011 This program is free software; you can redistribute it and/or 
00012 modify it under the terms of the GNU General Public License 
00013 as published by the Free Software Foundation; either 
00014 version 2 of the License, or (at your option) any later 
00015 version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License
00023 along with this program; if not, write to the Free Software
00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025  ***************************************************************************/
00026 
00027 #include "di194.h"
00028 
00042 di194_dsdk::di194_dsdk():dsdk()
00043 {
00044   chan_order[0] = 0;
00045   m_ADChannelCount = 1;
00046   // create new lists
00047   m_ADChannelList = new int[m_ADChannelCount];
00048   m_ADMethodList = new int[m_ADChannelCount];
00049   for(int i=0; i<m_ADChannelCount; i++)
00050   {
00051     m_ADChannelList[i] = i;
00052     m_ADMethodList[i] = IOS_AVERAGE;
00053     chan_order[i] = i * DI194_CHAN_SIZE;
00054   }
00055 
00056   digital_chan = false;
00057 
00058   m_MaxBurstRate = 240.00;
00059   // set to default sample rate based on channels activated
00060   SampleRate(m_SampleRate);
00061 }
00062 
00067 di194_dsdk::~di194_dsdk()
00068 {
00069   DeviceDisconnect();
00070 
00071   if(m_ADChannelList != 0)
00072   {
00073     delete [] m_ADChannelList;
00074     m_ADChannelList = 0;
00075   }
00076   if(m_ADDiffList != 0)
00077   {
00078     delete [] m_ADDiffList;
00079     m_ADDiffList = 0;
00080   }
00081   if(m_ADGainList != 0)
00082   {
00083     delete [] m_ADGainList;
00084     m_ADGainList = 0;
00085   }
00086   if(m_ADMethodList != 0)
00087   {
00088     delete [] m_ADMethodList;
00089     m_ADMethodList = 0;
00090   }
00091   if(m_device_file != 0)
00092   {
00093     delete [] m_device_file;
00094     m_device_file = 0;
00095   }
00096 }
00097 
00098 // Get "Properties"
00099 
00103 const int di194_dsdk::ADChannelCount()
00104 {
00105   return m_ADChannelCount;
00106 }
00107 
00112 const long int di194_dsdk::AvailableData()
00113 {
00114   // no data if not acquiring
00115   if(!m_acquiring_data)
00116     return 0;
00117 
00118   return m_connection.bytes_in_receive()/DI194_CHAN_SIZE; 
00119 }
00120 
00124 const long int di194_dsdk::EventPoint()
00125 {
00126   return m_EventPoint;
00127 }
00128 
00142 const char *const di194_dsdk::InfoSerial()
00143 {
00144   // can't get serial number while acquiring data
00145   if(m_acquiring_data)
00146   {
00147     m_last_error = EBUSY;
00148     return 0;
00149   }
00150   // must be connected
00151   if(!m_connection.is_comm_open())
00152   {
00153     m_last_error = ENOLINK;
00154     return 0;
00155   }
00156 
00157   char *sn = new char[DI194_SN_LENGTH];
00158   if(!Ncmd(m_connection, sn))
00159     m_last_error = my_errno;
00160 
00161   return sn;
00162 }
00163 
00167 const double di194_dsdk::SampleRate()
00168 {
00169   return m_SampleRate;
00170 }
00171 
00172 // Set "Properties"
00173 
00202 void di194_dsdk::ADChannelCount(const int ChannelCount)
00203 {
00204   // can't set while acquiring data
00205   if(m_acquiring_data)
00206   {
00207     m_last_error = EBUSY;
00208     return;
00209   }
00210   // must be connected
00211   if(!m_connection.is_comm_open())
00212   {
00213     m_last_error = ENOLINK;
00214     return;
00215   }
00216   // bounds check
00217   if(ChannelCount > DI194_CHANNELS || ChannelCount < 1)
00218   {
00219     m_last_error = EBOUNDS;
00220     return;
00221   }
00222   // pointer check
00223   if(m_ADChannelList != 0)
00224   {
00225     delete [] m_ADChannelList;
00226     m_ADChannelList = 0;
00227   }
00228   // pointer check
00229   if(m_ADMethodList != 0)
00230   {
00231     delete [] m_ADMethodList;
00232     m_ADMethodList = 0;
00233   }
00234 
00235   m_ADChannelCount = ChannelCount;
00236   m_ADChannelList = new int[m_ADChannelCount];
00237   m_ADMethodList = new int[m_ADChannelCount];
00238   // initialize with default values
00239   for(int i=0; i<m_ADChannelCount; i++)
00240   {
00241     m_ADChannelList[i] = i;
00242     m_ADMethodList[i] = IOS_AVERAGE;
00243   }
00244   
00245   // check if all channels requested
00246   // if so, change last channel to digital
00247   if(m_ADChannelCount == DI194_CHANNELS)
00248   {
00249     m_ADChannelList[DI194_CHANNELS-1] = -1;
00250     // 'all channels' includes digital ports
00251     digital_chan = true;
00252     // last point makes more sense for digital
00253     m_ADMethodList[DI194_CHANNELS-1] = IOS_LAST_POINT;
00254     // setup channel order (used in conversion)
00255     for(int i=0; i<DI194_CHANNELS-1; i++)
00256       chan_order[i] = i;
00257   }
00258   else // no digital
00259   {
00260     digital_chan = false;
00261     for(int i=0; i<m_ADChannelCount; i++)
00262       chan_order[i] = i;
00263   }
00264 
00265   // set sample rate according to new channels
00266   SampleRate(m_SampleRate);
00267 
00268   /* set channels to scan for acquisition
00269   1   -   analog channel 1
00270   2   -   analog channel 2
00271   4   -   analog channel 3
00272   8   -   analog channel 4
00273 
00274   add together to get any combination of channels
00275       OR
00276   each bit is a channel: 4 (left) to 1 (right) using above scheme
00277   channel 1, binary: 0001     (decimal: 1)
00278   channel 2,3 binary: 0110    (decimal: 6) */
00279   u_int8_t chan = 0;
00280   for(int i=0; i<m_ADChannelCount; i++)
00281   {
00282     if(m_ADChannelList[i] > -1)
00283       chan |= (0x01 << m_ADChannelList[i]);
00284   }
00285   // enable digital channel input
00286   if(digital_chan)
00287   {
00288     if(!Dcmd(m_connection, 1))
00289     {
00290       m_last_error = my_errno;
00291       return;
00292     }
00293   }
00294   else  // disable digital channel input
00295   {
00296     if(!Dcmd(m_connection, 0))
00297     {
00298       m_last_error = my_errno;
00299       return;
00300     }
00301   }
00302   // enable analog channels
00303   if(!Ccmd(m_connection, chan))
00304   {
00305     m_last_error = my_errno;
00306     return;
00307   }
00308 }
00309 
00314 void di194_dsdk::EventPoint(const long int EventPnt)
00315 {
00316   if(EventPnt < 0)
00317     m_EventPoint = 0;
00318   else if(EventPnt > 32767)
00319     m_EventPoint = 32767;
00320   else
00321     m_EventPoint = EventPnt;
00322   
00323   return;
00324 }
00325 
00337 void di194_dsdk::SampleRate(const double SampleRt)
00338 {
00339   // can't set while acquiring data
00340   if(m_acquiring_data)
00341   {
00342     m_last_error = EBUSY;
00343     return;
00344   }
00345 
00346   double maxsr = 0;
00347   double minsr = 0;
00348   
00349   if(digital_chan)  // don't include digital channel in count
00350   {
00351     if(m_ADChannelCount == 1)
00352     {
00353       maxsr = DI194_MAXBURSTRATE; // don't divide by 0
00354       minsr = DI194_MINBURSTRATE; // don't multiply by 0
00355     }
00356     else
00357     { // subtract out the digital channel
00358       maxsr = DI194_MAXBURSTRATE / (m_ADChannelCount - 1);
00359       minsr = DI194_MINBURSTRATE * (m_ADChannelCount - 1);
00360     }
00361   }
00362   else  // no digital channel to worry about
00363   {
00364     maxsr = DI194_MAXBURSTRATE / m_ADChannelCount;
00365     minsr = DI194_MINBURSTRATE * m_ADChannelCount;
00366   }
00367   // user wants minimum, set to minimum
00368   if(SampleRt <= minsr)
00369     m_SampleRate = minsr;
00370   // user wants maximum, set to maximum
00371   else if(SampleRt >= maxsr)
00372     m_SampleRate = maxsr;
00373   else  // inbetween, user is within bounds
00374     m_SampleRate = SampleRt;
00375 }
00376 
00377 // "Methods"
00378 
00403 void di194_dsdk::ADChannelList(const int *const ChannelList)
00404 {
00405   // can't set while acquiring data
00406   if(m_acquiring_data)
00407   {
00408     m_last_error = EBUSY;
00409     return;
00410   }
00411   // must be connected
00412   if(!m_connection.is_comm_open())
00413   {
00414     m_last_error = ENOLINK;
00415     return;
00416   }
00417   // pointer check
00418   if(ChannelList == 0)
00419   {
00420     m_last_error = EINVAL;
00421     return;
00422   }
00423   // used to check if multiple digital channels are specified,
00424   // there shouldn't be
00425   bool check_digital = false;
00426   // bounds check
00427   for(int i=0; i<m_ADChannelCount; i++)
00428   {
00429     if(ChannelList[i] >= DI194_CHANNELS-1 || ChannelList[i] < -1)
00430     {
00431       m_last_error = EBOUNDS;
00432       return;
00433     }
00434     // make sure only one digital channel is specified
00435     if(ChannelList[i] == -1 && !check_digital)
00436       check_digital = true;
00437     else if(ChannelList[i] == -1)
00438     {
00439       m_last_error = EBOUNDS;
00440       return;
00441     }
00442   }
00443 
00444   // must have at least one analog channel enabled
00445   if(m_ADChannelCount == 1 && check_digital)
00446   {
00447     m_last_error = EBOUNDS;
00448     return;
00449   }
00450 
00451   // temporary, used for setting up channel order
00452   int temp_chan[DI194_CHANNELS] = {0};
00453 
00454   // set digital channel setting to what was determined in bounds check
00455   digital_chan = check_digital;
00456 
00457   // copy the channel list
00458   for(int i=0; i<m_ADChannelCount; i++)
00459   {
00460     m_ADChannelList[i] = ChannelList[i];
00461     temp_chan[i] = ChannelList[i];
00462   }
00463 
00464   // sort channel list, it's only 5 channels max,
00465   // bubble sort will work
00466   for(int i=1; i<m_ADChannelCount; i++)
00467   {
00468     for(int j=0; j<m_ADChannelCount-i; j++)
00469     {
00470       if(temp_chan[j] > temp_chan[j+1]) // need to swap?
00471       {
00472         temp_chan[j] = temp_chan[j] ^ temp_chan[j+1];
00473         temp_chan[j+1] = temp_chan[j] ^ temp_chan[j+1];
00474         temp_chan[j] = temp_chan[j] ^ temp_chan[j+1];
00475       }
00476     }
00477   }
00478 
00479   if(digital_chan)
00480   {
00481     // setup channel order
00482     for(int i=1; i<m_ADChannelCount; i++)
00483       chan_order[temp_chan[i]] = (i-1) * DI194_CHAN_SIZE;
00484   }
00485   else
00486   {
00487     // setup channel order
00488     for(int i=0; i<m_ADChannelCount; i++)
00489         chan_order[temp_chan[i]] = i * DI194_CHAN_SIZE;
00490   }
00491 
00492   /* set channels to scan for acquisition
00493   1   -   analog channel 1
00494   2   -   analog channel 2
00495   4   -   analog channel 3
00496   8   -   analog channel 4
00497 
00498   add together to get any combination of channels
00499       OR
00500   each bit is a channel: 4 (left) to 1 (right) using above scheme
00501   channel 1, binary: 0001     (decimal: 1)
00502   channel 2,3 binary: 0110    (decimal: 6) */
00503   u_int8_t chan = 0;
00504   for(int i=0; i<m_ADChannelCount; i++)
00505   {
00506     if(m_ADChannelList[i] != -1)
00507       chan |= (0x01 << m_ADChannelList[i]);
00508   }
00509   // enable digital channel input
00510   if(digital_chan)
00511   {
00512     if(!Dcmd(m_connection, 1))
00513     {
00514       m_last_error = my_errno;
00515       return;
00516     }
00517   }
00518   else  // disable digital channel input
00519   {
00520     if(!Dcmd(m_connection, 0))
00521     {
00522       m_last_error = my_errno;
00523       return;
00524     }
00525   }
00526   // enable analog channels
00527   if(!Ccmd(m_connection, chan))
00528   {
00529     m_last_error = my_errno;
00530     return;
00531   }
00532 }
00533 
00548 void di194_dsdk::ADMethodList(const int *const MethodList)
00549 {
00550   // can't set while acquiring data
00551   if(m_acquiring_data)
00552   {
00553     m_last_error = EBUSY;
00554     return;
00555   }
00556   // pointer check
00557   if(MethodList == 0)
00558   {
00559     m_last_error = EINVAL;
00560     return;
00561   }
00562 
00563   // bounds check
00564   for(int i=0; i<m_ADChannelCount; i++)
00565   {
00566     if(MethodList[i] > IOS_GREATEST || MethodList[i] < IOS_SMALLEST)
00567     {
00568       m_last_error = EBOUNDS;
00569       return;
00570     }
00571   }
00572 
00573   // copy the list
00574   for(int i=0; i<m_ADChannelCount; i++)
00575     m_ADMethodList[i] = MethodList[i];
00576 }
00577 
00593 void di194_dsdk::DeviceConnect()
00594 {
00595   // can't set while acquiring data
00596   if(m_acquiring_data)
00597   {
00598     m_last_error = EBUSY;
00599     return;
00600   }
00601   // device file hasn't been set
00602   if(m_device_file == 0)
00603   {
00604     m_last_error = ENODEV;
00605     return;
00606   }
00607   // already connected
00608   if(m_connection.is_comm_open())
00609   {
00610     m_last_error = EALREADY;
00611     return;
00612   }
00613 
00614   // open the serial port
00615   // setup the serial port
00616   my_errno = m_connection.connect(m_device_file, 1);
00617   if(my_errno != 0)
00618   {
00619     m_last_error = my_errno;
00620     DeviceDisconnect();
00621     return;
00622   }
00623 
00624   // make sure device is stopped
00625   m_acquiring_data = true;
00626   Stop();
00627 }
00628 
00640 void di194_dsdk::DeviceDisconnect()
00641 {
00642   // check if user forgot to stop acquiring
00643   if(m_acquiring_data)
00644     // stop acquiring first
00645     Stop();
00646   m_acquiring_data = false;
00647   // check if already disconnected
00648   if(!m_connection.is_comm_open())
00649     return;
00650   // restore original serial port settings and
00651   // try to close the serial port
00652   m_last_error = m_connection.disconnect();
00653 }
00654 
00685 void di194_dsdk::GetDataEx(short int *iArray, const int Count)
00686 {
00687   // bounds check
00688   if(Count > 32767 || Count < 1)
00689   {
00690     m_last_error = EBOUNDS;
00691     return;
00692   }
00693   // pointer check
00694   if(iArray == 0)
00695   {
00696     m_last_error = EINVAL;
00697     return;
00698   }
00699   // must be acquiring
00700   if(!m_acquiring_data)
00701   {
00702     m_last_error = ENODATA;
00703     return;
00704   }
00705 
00706   u_int8_t di_data[DI194_CHAN_SIZE*(DI194_CHANNELS-1)] = {0};
00707   int mCount = 0;
00708   // number of oversamples per real sample
00709   int srinterval = static_cast<int>(m_MaxBurstRate/ (digital_chan
00710                                           ? m_ADChannelCount-1
00711                                           : m_ADChannelCount)
00712                                            + 1 - m_SampleRate);
00713   if(srinterval <= 0)
00714     srinterval = 1;
00715   // temporarily holds original data to perform calculation
00716   short int temp[DI194_CHANNELS] = {0};
00717   // in case user asks for less data points than in a normal scan
00718   int small_sample = m_ADChannelCount < Count ? m_ADChannelCount : Count;
00719   // holds intermittent values for IOS_AVERAGE
00720   int64_t ios_avg[DI194_CHANNELS] = {0};
00721   bool first_time = true;
00722   u_int16_t amount = 0;
00723   if(digital_chan) // digital channel is embedded
00724   {
00725     amount = DI194_CHAN_SIZE*(m_ADChannelCount-1);
00726   }
00727   else  // no digital channel
00728   {
00729     amount = DI194_CHAN_SIZE*m_ADChannelCount;
00730   }
00731 
00732   // loop until enough data points have been gathered,
00733   // as far as blocks of enabled channels go
00734   for(int c=0, d=0, e=0; c<Count; c += small_sample, d=0)
00735   {
00736     first_time = true;
00737     for(e=0; e<small_sample; e++)
00738       ios_avg[e] = 0;
00739 
00740     // loop until the right number of samples have been gathered for
00741     // the specific sample rate
00742     for(int timer=0; timer<srinterval; timer++)
00743     {
00744       // get data
00745       if(m_connection.di_read(&di_data[0], amount, static_cast<u_int8_t>(amount)))
00746       {
00747         m_last_error = my_errno; // error occurred
00748         return;
00749       }
00750       // copy original values
00751       for(e=0; e<small_sample; e++)
00752         temp[e] = iArray[c+e];
00753       // convert new data to counts and store in array
00754       for(e=0; e<small_sample; e++)
00755         iArray[c + e] = static_cast<short int>(convert(&di_data[0], e));
00756       // increment number of oversamples per scan
00757       d++;
00758       // don't perform any calculations the first time through
00759       if(first_time)
00760       {
00761         first_time = false;
00762         for(e=0; e<small_sample; e++)
00763           ios_avg[e] += iArray[c+e];
00764         continue;
00765       }
00766       // apply method to 'original' and 'new' data values
00767       for(e=0; e<small_sample; e++)
00768       {
00769         switch(m_ADMethodList[e])
00770         {
00771           case IOS_RMS:  // not implemented
00772           case IOS_FREQ: // not implemented
00773           case IOS_LAST_POINT:  // last point
00774             // this happens by default, nothing to do
00775             break;
00776           case IOS_AVERAGE: // average of points
00777             ios_avg[e] += iArray[c+e];     // adds up values, after conversion above
00778             iArray[c+e] = ios_avg[e] / d;  // stores new average
00779             break;
00780           case IOS_MIN: // minimum of points
00781             if(temp[e] < iArray[c+e])
00782               iArray[c+e] = temp[e];
00783             break;
00784           case IOS_MAX: // maximum of points
00785             if(temp[e] > iArray[c+e])
00786               iArray[c+e] = temp[e];
00787             break;
00788         }
00789       }
00790     }
00791   }
00792 
00793   // any amount left that wasn't an even divisor of scanned blocks?
00794   // just use the next scanned packet
00795   mCount = Count % m_ADChannelCount;
00796   if(mCount != 0) // true if not done
00797   {
00798     // grab some more data
00799     if(m_connection.di_read(&di_data[0], amount, static_cast<u_int8_t>(amount)))
00800     {
00801       m_last_error = my_errno; // error occurred
00802       return;
00803     }
00804     // and store part of it
00805     for(int e=0; e<mCount; e++)
00806       iArray[Count - mCount + e] = static_cast<short int>(convert(&di_data[0], e));
00807   }
00808 }
00809 
00822 void di194_dsdk::Start()
00823 {
00824   // don't send command if already acquiring, this is an error because
00825   // there is data in the buffer
00826   if(m_acquiring_data)
00827   {
00828     m_last_error = EALREADY;
00829     return;
00830   }
00831   if(!m_connection.is_comm_open()) // don't bother if not connected
00832   {
00833     m_last_error = ENOLINK;
00834     return;
00835   }
00836 
00837   // send command
00838   if(!Scmd(m_connection, 1))
00839   {
00840     m_last_error = my_errno;
00841     return;
00842   }
00843 
00844   m_acquiring_data = true;
00845 }
00846 
00858 void di194_dsdk::Stop()
00859 {
00860   // can't set while not acquiring data,
00861   // not really an error
00862   if(!m_acquiring_data)
00863     return;
00864   // must be connected
00865   if(!m_connection.is_comm_open())
00866   {
00867     m_last_error = ENOLINK;
00868     return;
00869   }
00870 
00871   // send command
00872   if(!Scmd(m_connection))
00873   {
00874     m_last_error = my_errno;
00875     return;
00876   }
00877 
00878   m_acquiring_data = false;
00879 }
00880 
00881 // "Event Occur" Methods
00882 
00894 const bool di194_dsdk::OverRun()
00895 {
00896   // must be connected
00897   if(!m_connection.is_comm_open())
00898   {
00899     m_last_error = ENOLINK;
00900     return false;
00901   }
00902 
00903   // doesn't set an error because this function represents an error
00904   if(m_connection.bytes_in_receive() >= DI_SERIAL_BUFFER_SIZE)
00905     return true;
00906 
00907   return false;
00908 }
00909 
00916 const short int di194_dsdk::convert(const u_int8_t *const di_data,
00917                                     const u_int8_t num_chan)
00918 {
00919   short int temp = 0;
00920   // extract and convert to counts
00921   // find out whether it's an analog or digital channel
00922   if(m_ADChannelList[num_chan] != -1) // analog channel
00923   {
00924     temp = static_cast<short int>(di_data[chan_order[m_ADChannelList[num_chan]]]
00925                    & 0xE0) >> 5;
00926     temp |= (static_cast<short int>(di_data[chan_order[m_ADChannelList[num_chan]]+1]
00927                    & 0xFE) << 2);
00928     temp <<= 6; // left justify the number
00929     temp ^= 0x8000;
00930   }
00931   else // digital bits
00932     temp = (di_data[0] & 0x0E) >> 1;
00933 
00934   return temp;
00935 }
00936 

Generated on Mon Aug 2 09:44:49 2004 for DataqSDK by doxygen 1.3.6