ACQ2XX_API
KddTransport.cpp
Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* file KddTransport.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 KddTransport.cpp defines the Kernel Device Driver Transport.
00022  * D-TACQ offers 2 types of Linux Kernel Device Driver, this Transport is
00023  * compatible with both of them:
00024  * - PCI backplane driver, for shared memory space systems.
00025  * - dt100-hub Network driver, emulates the PCI driver but with no shared
00026  *   memory, no plugin cards.
00027  *
00028  * D-TACQ does NOT offer a Windows(TM) kernel device driver (WDM) at this
00029  * time; to control ACQ2xx from Windows use the SOAP or Dt100Transports.
00030  */
00031 #include "local.h"
00032 #include <errno.h>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include "acq_transport.h"
00037 #include "KddTransport.h"
00038 
00039 
00040 
00041 #define MFMT "/dev/acq32/acq32.%d.m%d"
00042 #define SHELL_FMT "/dev/acq200/acq200.%d.rsh"
00043 
00044 #define ERROR_STRING    "ACQ32:ERROR"
00045 #define ERROR_LEN       strlen(ERROR_STRING)
00046 
00047 
00048 
00049 class KddTransport: public Transport {
00050 /** Transport implementation connects to locate linux Kernel Device Driver. */  
00051         FILE* fd_cmd;
00052         FILE* fd_shell;
00053 
00054         STATUS processCommand(
00055                 FILE* fd,
00056                 const char* command, char *response, int maxresponse)   
00057         {
00058 
00059                 dbg(1, "->%s", command);
00060 
00061                 fputs(command, fd);
00062                 if (command[strlen(command)-1] != '\n'){
00063                         fputs("\n", fd);
00064                 }
00065 
00066                 char reply[80];         
00067                 int nout;
00068                 int err = STATUS_OK;
00069                 char* pr = response;
00070                 int complete = 0;
00071 
00072                 *pr = '\0';
00073 
00074                 for (nout = 0; fgets(reply, sizeof(reply), fd) != NULL; ++nout){
00075 
00076                         dbg(1, "<-%s", reply);
00077 
00078                         if (strncmp(reply, ERROR_STRING, ERROR_LEN) == 0){
00079                                 err = -1;
00080                         }
00081                         if (STREQN(reply, "EOF", 3)){
00082                                 complete = 1;
00083                                 break;
00084                         }
00085 
00086                         int headroom = maxresponse - (pr - response);
00087                         strncpy(pr, reply, headroom);
00088                         pr += strlen(pr);
00089                 }
00090 
00091                 dbg(2, "nout %d len %d err %d", nout, pr-response, err);
00092 
00093                 if (!complete){
00094                         err("incomplete response %s", response);
00095                         if (nout == 0){
00096                                 perror( "zero chars");
00097                         }
00098                         return -1;
00099                 }else if (STATUS_ERR(err)){
00100                         return err;
00101                 }else{
00102                         if (*(pr-1) == '\n'){
00103                                 *--pr = '\0';
00104                         }
00105                         return pr - response;
00106                 }
00107         }
00108 
00109         char channel_dev[80];
00110         FILE *fp_data;
00111 
00112         const int slot;
00113         char cmd_dev[80];
00114         char shell_dev[80];
00115 
00116 private:
00117         void closeSession(FILE* &fd){
00118                 if (fd){
00119                         fclose(fd);
00120                         fd = 0;
00121                 }
00122         }
00123         void openSession(FILE* &fd, char* dev){
00124                 closeSession(fd);
00125                 fd = fopen(dev, "r+");
00126                 if (fd == 0){
00127                         die(errno, dev);
00128                 }
00129         }
00130 protected:
00131         void openShellSession() {
00132                 openSession(fd_shell, shell_dev);
00133         }
00134         void closeShellSession() {
00135                 closeSession(fd_shell);
00136         }
00137         void openCmdSession() {
00138                 openSession(fd_cmd, cmd_dev);
00139         }
00140         void closeCmdSession() {
00141                 closeSession(fd_cmd);
00142         }
00143 
00144 public:
00145         KddTransport(const char* id):   
00146         Transport(id),  fd_cmd(0), fd_shell(0), fp_data(0), slot(atoi(id))
00147         {
00148                 memset(channel_dev, 0, sizeof(channel_dev));
00149                 
00150                 sprintf(cmd_dev, MFMT, slot, slot);
00151                 sprintf(shell_dev, SHELL_FMT, slot);
00152 
00153                 openShellSession();
00154                 openCmdSession();
00155         }
00156         ~KddTransport() {
00157                 closeShellSession();
00158                 closeCmdSession();
00159         }
00160 
00161         virtual STATUS acqcmd(
00162                 const char* command, char *response, int maxresponse)
00163         /**< send an "acqcmd" (acquisition command or query) to the card.
00164          * @param command - the command (or query) to send
00165          * @param response - user buffer to collect response.
00166          * @param maxresponse - maximum response size required.
00167          */
00168         {
00169                 return processCommand(fd_cmd, command, response, maxresponse);
00170         }
00171 
00172         virtual STATUS acq2sh(
00173                 const char* command, char *response, int maxresponse)
00174         /**< run a remote shell command or query. 
00175          * @param command - the command (or query) to send
00176          * @param response - user buffer to collect response.
00177          * @param maxresponse - maximum response size required.
00178          */
00179         {
00180                 return processCommand(fd_shell, command, response, maxresponse);
00181         }
00182 
00183         virtual STATUS waitStateChange(
00184                 int timeout, char* response, int maxresponse)
00185         /**< block until remote state changes or timeout. */
00186         {
00187                 return STATUS_WORKTODO;
00188         }
00189 
00190         virtual STATUS readChannel(
00191                 int channel, short* data,
00192                 int nsamples, int start = 0, int stride = 1)
00193         /**< read and output raw data for channel
00194          * @param channel - channel number 1..N
00195          * @param data - caller's buffer
00196          * @param nsamples - max samples to read
00197          * @param start - start sample in data set
00198          * @param stride - stride [subsample] value
00199          * @returns actual samples returned or STATUS_ERR
00200          * @todo - start, stride dont work at this time
00201          */
00202         {
00203                 char _channel_dev[80];
00204                 sprintf(_channel_dev, "/dev/acq32/acq32.%d.%02d", 
00205                         slot, channel);
00206 
00207                 if (fp_data != 0){
00208                         if (strcmp(_channel_dev, channel_dev) == 0){
00209                                 ;
00210                         }else{
00211                                 fclose(fp_data);
00212                                 fp_data = 0;
00213                         }
00214                 }
00215                 if (fp_data == 0){
00216                         strcpy(channel_dev, _channel_dev);
00217                         fp_data = fopen(channel_dev, "r");
00218                         if (fp_data == 0){
00219                                 perror(channel_dev);
00220                                 return errno;
00221                         }
00222                 }
00223                 return fread(data, sizeof(short), nsamples, fp_data);
00224         }
00225 };
00226 
00227 
00228 class HostdrvTransport: public KddTransport {
00229 /** HOSTDRV doesn't handle multiple writes on one shell session, so we
00230  *  decorate KddTransport, to start a new session each time.
00231  *  This is a HOSTDRV defect, but sessions are cheap on HOSTDRV..
00232  *  @todo BEWARE: state polling can be too fast 
00233  */
00234 public:
00235         HostdrvTransport(const char* id):
00236                 KddTransport(id)
00237         {}
00238 
00239         virtual STATUS acq2sh(
00240                 const char* command, char *response, int maxresponse)
00241         /**< run a remote shell command or query. 
00242          * @param command - the command (or query) to send
00243          * @param response - user buffer to collect response.
00244          * @param maxresponse - maximum response size required.
00245          */
00246         {
00247                 openShellSession();
00248                 int rc = KddTransport::acq2sh(command, response, maxresponse);
00249                 closeShellSession();
00250                 return rc;
00251         }
00252         
00253 };
00254 
00255 Transport* KddTransportFactory::createTransport(const char* id)
00256 /**< KddTransport Factory - create if id is a simple integer slot#. */
00257 {
00258         int slot = atoi(id);
00259         char slot_id[10];
00260         sprintf(slot_id, "%d", slot);
00261 
00262         if (strcmp(id, slot_id) == 0){
00263                 if (slot < 10){
00264                         return new HostdrvTransport(id);
00265                 }else{ 
00266                         return new KddTransport(id);
00267                 }
00268         }else{
00269                 return 0;
00270         }
00271 }