ACQ2XX_API
acqread.cpp
Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* file acqread.cpp                                                          */
00003 /* ------------------------------------------------------------------------- */
00004 /*   Copyright (C) 2008 Peter Milne, D-TACQ Solutions Ltd
00005  *                      <Peter dot Milne at D hyphen TACQ dot com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of Version 2 of the GNU General Public License
00009     as published by the Free Software Foundation;
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00019 /* ------------------------------------------------------------------------- */
00020 
00021 /** @file acqread.cpp channel upload example using API.
00022  *  usage: acqread [opts] ch1[..chN] [length] [start] [stride]
00023  *  
00024  *  - ch1..chN : channel selection eg 1..32
00025  *  - length   : #samples to upload [default: all]
00026  *  - start    : start sample [default: 0]
00027  *  - stride   : stride [interval, subsample] value [default:1]
00028  *  - opts:
00029  *   - --url URL : URL of device
00030  *   - --device d: device name
00031  *   - --board  b: board number b [integer dvice index]
00032  *   - --slot   s: slot number s [now same as board]
00033  *   - --output file : output to file, can be sprintf() format eg file.%02d
00034  *   - --verbose : set verbose [debug] level
00035  *   - --version : print version
00036  *
00037  * example:
00038  @verbatim
00039 
00040 # localhost:10009 is an ssh port-forward tunnel to target:53504
00041 
00042 # read raw data channels 1-8, 1000 samples
00043 
00044 ./x86/bin/acqread -o /tmp/data.%02d -f localhost:10009 1-8 1000
00045 ls -l /tmp/data.0?
00046 -rw-rw-r-- 1 pgm pgm 2000 2008-05-12 11:38 /tmp/data.01
00047 ..
00048 -rw-rw-r-- 1 pgm pgm 2000 2008-05-12 11:38 /tmp/data.08
00049 
00050 hexdump -e '4/2 "%04x " "\n"' </tmp/data.01 | head
00051 ffd2 ffd3 ffd0 ffd0
00052 ffd4 ffcd ffd0 ffd1
00053 ffd4 ffd2 ffd7 ffd0
00054 
00055 # read volts channels 1-8, 1000 samples
00056 
00057 ./x86/bin/acqread -o /tmp/volts.%02d -V -f localhost:10009 1-8 1000
00058 
00059 ls -l /tmp/volts.0?
00060 -rw-rw-r-- 1 pgm pgm 4000 2008-05-12 11:45 /tmp/volts.01
00061 ..
00062 -rw-rw-r-- 1 pgm pgm 4000 2008-05-12 11:45 /tmp/volts.08
00063 
00064 hexdump -e '4/4 "%f " "\n"' </tmp/volts.01 | head
00065 0.149466 0.149778 0.148840 0.148840
00066 0.150091 0.147902 0.148840 0.149153
00067 0.150091 0.149466 0.151030 0.148840
00068 
00069 @endverbatim
00070  */
00071 
00072 #include "local.h"
00073 
00074 #include <errno.h>
00075 
00076 #include "acq2xx_api.h"
00077 #include "acq_transport.h"
00078 
00079 #include "popt.h"
00080 
00081 int acq200_debug;
00082 char *device;
00083 poptContext opt_context;
00084 
00085 #define MAXBUF 1024
00086 char command[MAXBUF] = {};
00087 char response[MAXBUF] = {};
00088 
00089 #define DBUF 0x100000
00090 short dbuf[DBUF];
00091 
00092 int channel1 = 1;
00093 int channel2 = 1;
00094 int start = 0;
00095 int length = 0;
00096 int stride = 1;
00097 
00098 enum IARG {
00099         I_CHANNEL,
00100         I_LENGTH,
00101         I_START,
00102         I_STRIDE
00103 };
00104 
00105 const char* outfile = "-";
00106 
00107 static void channel_decode(const char* range)
00108 {
00109         if (sscanf(range, "%d-%d", &channel1, &channel2) == 2 ||
00110             sscanf(range, "%d..%d", &channel1, &channel2) == 2  ){
00111                 return;
00112         }else if (sscanf(range, "%d", &channel1) == 1){
00113                 channel2 = channel1;
00114                 return;
00115         }else{
00116                 err("failed to decode channel \"%s\"", range);
00117         }           
00118 }
00119 
00120 
00121 class FetchesData {
00122 
00123 public:
00124         const int dsize;
00125 
00126         FetchesData(int _dsize): dsize(_dsize) 
00127         {}
00128         virtual ~FetchesData()
00129         {}
00130 
00131         virtual int readChannel(
00132                 Acq2xx& card,
00133                 int ch, void* dbuf, int nread, int start, int stride) = 0;
00134 };
00135 
00136 class FetchesRaw : public FetchesData {
00137 public:
00138         FetchesRaw() : FetchesData(sizeof(short)) 
00139         {
00140         }
00141         virtual int readChannel(
00142                 Acq2xx& card,
00143                 int ch, void* dbuf, int nread, int start, int stride) 
00144         {
00145                 return card.readChannel(ch, (short*)dbuf, nread, start, stride);
00146         }
00147 };
00148 
00149 class FetchesVolts : public FetchesData {
00150 public:
00151         FetchesVolts() : FetchesData(sizeof(float))
00152         {
00153 
00154         }
00155         virtual int readChannel(
00156                 Acq2xx& card,
00157                 int ch, void* dbuf, int nread, int start, int stride) 
00158         {
00159                 return card.readChannelVolts(
00160                                 ch, (float*)dbuf, nread, start, stride);
00161         }       
00162 };
00163 class ChannelReader {
00164 protected:
00165         Acq2xx& card;
00166         FetchesData& fetcher;
00167         FILE *fpout;
00168 
00169         void getoutfile(int channel)
00170         {
00171                 if (strcmp(outfile, "-") == 0){
00172                         fpout = stdout;                
00173                 }else{
00174                         char fname[128];
00175                         sprintf(fname, outfile, channel);
00176                         if (strcmp(fname, outfile) == 0 && fpout != 0){
00177                                 ; return;       // use same file
00178                         }
00179 
00180                         if (fpout){
00181                                 fclose(fpout);
00182                         }               
00183 
00184                         fpout = fopen(fname, "w");
00185                         if (fpout == 0){
00186                                 err("unable to open file \"%s\"", fname);
00187                                 exit(errno);
00188                         }
00189                 }
00190         }
00191 
00192 public:
00193 ChannelReader(Acq2xx& _card, FetchesData& _fetcher) :
00194         card(_card), fetcher(_fetcher), fpout(0)
00195         {
00196         }
00197 
00198 
00199         int read_channel(int ch) {
00200                 getoutfile(ch);
00201         
00202                 int nread = -1;
00203 
00204                 for (int total = 0; total < length; total += nread){
00205                         nread = MIN(DBUF, length-total);
00206                         nread = fetcher.readChannel(
00207                                 card, ch, dbuf, nread, start+total, stride);
00208 
00209                         if (nread > 0){
00210                                 fwrite(dbuf, fetcher.dsize, nread, fpout);
00211                                 continue;
00212                         }else if (nread < 0){
00213                                 err("readChannel returns ERROR %d", nread);
00214                                 exit(errno);
00215                         }else if (nread == 0){
00216                                 err("readChannel() reaturns 0 at %d", total);
00217                                 break;
00218                         }
00219                 }       
00220 
00221                 return nread;
00222         }
00223 };
00224 
00225 int main(int argc, const char** argv)
00226 {
00227         struct poptOption opt_table[] = {
00228                 { "url",        'u', POPT_ARG_STRING, &device,     'u' },
00229                 { "device",     'f', POPT_ARG_STRING, &device,     'f' },
00230                 { "board",      'b', POPT_ARG_STRING, &device,      'b' },
00231                 { "shell",      's', POPT_ARG_STRING, &device,      's' },
00232                 { "output",     'o', POPT_ARG_STRING, &outfile,    },
00233                 { "volts",      'V', POPT_ARG_NONE,   0, 'V' },
00234                 { "verbose",    'v', POPT_ARG_INT,    &acq200_debug, 0},
00235                 { "version",    0,   POPT_ARG_NONE,   0,           'V' },
00236                 POPT_AUTOHELP
00237                 POPT_TABLEEND           
00238         };
00239         int rc;
00240         FetchesData *fetcher = new FetchesRaw();
00241 
00242         opt_context = poptGetContext( argv[0], argc, argv, opt_table, 0 );
00243         while ( (rc = poptGetNextOpt( opt_context )) > 0 ){
00244                 switch( rc ){
00245                 case 'V':
00246                         fetcher = new FetchesVolts();
00247                         break;
00248                 default:
00249                         ;
00250                 }
00251         }
00252 
00253 
00254         for (int iarg = 0; poptPeekArg(opt_context); ++iarg){
00255                 const char* arg = poptGetArg(opt_context);
00256                 switch(iarg){
00257                 case I_CHANNEL:
00258                         channel_decode(arg);
00259                         break;
00260                 case I_LENGTH:
00261                         length = strtoul(arg, 0, 0);
00262                         break;
00263                 case I_START:
00264                         start = strtoul(arg, 0, 0);
00265                         break;
00266                 case I_STRIDE:
00267                         stride = strtoul(arg, 0, 0);
00268                         break;
00269                 default:
00270                         err("too many args");
00271                         return -1;                      
00272                 }
00273         }
00274 
00275         if (device == 0){
00276                 err("usage acqread "
00277                     "channel[..channel2] [length] [start] [stride] ");
00278                 return -1;
00279         }
00280 
00281         Acq2xx card(Transport::getTransport(device));
00282 
00283         if (length == 0){
00284                 if (card.getNumSamples(&length) != STATUS_OK){
00285                         err("getNumSamples failed");
00286                         exit(errno);
00287                 }
00288         }
00289 
00290         ChannelReader reader(card, *fetcher);
00291 
00292         for (int ch = channel1; ch <= channel2; ++ch){
00293                 reader.read_channel(ch);
00294         }
00295 }