Pacific-Design.com

    
Home Index

1. Caltech

2. Comedi Broker

Caltech / Comedi Broker /

/*-----------------------------------------------------------------------------
     California Institute of Technology
     The Andersen Lab, Division of Biology

      Broker: 
       - Enable Communication between Comedi interface and Shared Memory.
       - Reading from Comedi Inteface and writting to the pipe
       - IPC connection Parent with Child
       - Terminate broker with signal with Child
               --------------------------------------
    Begin          : Thu July 31, 2001
    Written        : by Kevin Duraj
    Email          : kevin@vis.caltech.edu 
    Collaborator   : Bijan Pesaran 

-----------------------------------------------------------------------------*/
#include <stdio.h>
#include <math.h>
#include <comedilib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sched.h>
#include "examples.h"
#include "unpipc.h"
#include "RT.h"
#include "myshare.h"
/*-------------------------- Defining Constants -----------------------------*/
#define DEFAULT_NCHANS CH
#define MAX_NCHANS 64
/* #define BUF_SIZE 65536/16 */
#define BUF_SIZE 8192
#define DEFAULT_RANGE 1 /* [-5,5] range */
#define DEFAULT_AREF AREF_DIFF
#define DEFAULT_FREQ SR
#define DEFAULT_NSCANS 0
/*---------------------------------------------------------------------------*/
#define DEBUG printf("Line: %d\n", __LINE__);
/*---------------------------------------------------------------------------*/
unsigned int chanlist[MAX_NCHANS];
char buffer[BUF_SIZE];
void log_broker_pid(void);
void terminate(void);
pid_t child_process;
int set_real_time_priority(void);

/*---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
  /*--------------- Comedi device driver ------------------*/
  char *dev = "/dev/comedi0";
  // char *devicefile = "/dev/comedi0";
  comedi_t *device;
  comedi_cmd cmd;


  /*-------------- Reding buffer declaration --------------*/
  char *rdbuf;
  char *outbuf;
  int n_rdbuf   = 2*CH*16;
  int n_outbuf  = 2*CH*16;
  int verbose = 0;
  int ii = 0;
  unsigned long int period=8000;
  int total;

  /*-------------------------------------------------------*/
  char data_file[64];
  int fd_data=0, res=0;
  /*-------------------------------------------------------*/
  int range   = DEFAULT_RANGE;
  int aref    = DEFAULT_AREF;
  int nchans  = DEFAULT_NCHANS;
  double freq = DEFAULT_FREQ;
  int nscans  = DEFAULT_NSCANS;
  int i, ret, cnt;
  /*------------ IPC Variables ----------------------------*/
  int fd_pipe[2];

  /*-------------------- Initialization ---------------------*/
  memset(buffer,    '\0'  , sizeof(buffer));
  memset(data_file, '\0'  , sizeof(data_file));
  memset(&cmd,      '\0'  , sizeof(cmd));
  set_real_time_priority();

  /*----------------- Parsing Prameter Options ---------------*/
  while ((i = getopt(argc, argv, "o:f:n:s:r:gdch")) != EOF)
  {
    switch (i)
    {
      /*------------------ create output file -----------------*/
      case 'o':
        strcpy(data_file, optarg);
        fprintf(stderr,"Opening output data file: %s.\n",data_file);
        if ((fd_data = open(data_file, O_WRONLY | O_CREAT )) == -1)
        fprintf(stderr,"Error opening output data file: %s.\n",data_file);
      break;
      case 'f': freq   = atoi(optarg); break;
      case 'n': nchans = atoi(optarg); break;
      case 's': nscans = atoi(optarg); break;
      case 'r': range  = atoi(optarg); break;
      case 'g': aref   = AREF_GROUND;  break;
      case 'd': aref   = AREF_DIFF;    break;
      case 'c': aref   = AREF_COMMON;    break;
      case 'h':
      default:
      system("clear");

      fprintf(stderr,"\nUsage of the Broker:");
      fprintf(stderr,"\n\t-o data file");
      fprintf(stderr,"\n\t-f frequency");
      fprintf(stderr,"\n\t-n nchans");
      fprintf(stderr,"\n\t-s nscans");
      fprintf(stderr,"\n\t-r range");
      fprintf(stderr,"\n\t-h help\n\n");

      exit(1);

    } /* end if switch stmt */

  } /* end of while loop */

  if (argc > optind) dev = argv[optind];

  device = comedi_open(dev);
  if(!device) { fprintf(stderr,"Could not open device: %s.\n",dev); exit(EXIT_FAILURE); }

  cmd.subdev =  comedi_find_subdevice_by_type(device,COMEDI_SUBD_AI,0);
  if (cmd.subdev < 0) { fprintf(stderr,"No analog input subdevice found.\n"); exit(EXIT_FAILURE); }

  cmd.flags = 0;

  cmd.start_src      = TRIG_NOW;
  cmd.start_arg      = 0;

  cmd.scan_begin_src = TRIG_TIMER;
  cmd.scan_begin_arg = floor(1.0E9/freq);

  cmd.convert_src    = TRIG_TIMER;
  cmd.convert_arg    = 0;

  cmd.scan_end_src   = TRIG_COUNT;
  cmd.scan_end_arg   = nchans;

  if (nscans == 0) {
    cmd.stop_src   = TRIG_NONE;
    cmd.stop_arg   = 0;
  }
  else {
    cmd.stop_src   = TRIG_COUNT;
    cmd.stop_arg   = nscans;
  }

  for (cnt = 0; cnt < nchans; cnt++) chanlist[cnt]=CR_PACK(cnt,range,aref);

  /*----------------------- Interface Card Configuration ------------------------------*/

  cmd.chanlist = chanlist;
  cmd.chanlist_len = nchans;

  fcntl(comedi_fileno(device),F_SETFL,O_NONBLOCK);

  ret = comedi_command_test(device,&cmd);
  if(ret < 0) { fprintf(stderr,"Error testing comedi command, errno=%d\n",errno); exit(1);    }

  ret = comedi_command(device,&cmd);
  if(ret < 0) { fprintf(stderr,"Error evaluating comedi command, errno=%d\n",errno); exit(1); }

  /*==================== Create Pipe Between Two Processes ==================*/
  if(pipe(fd_pipe) == 0)
  {
    child_process = fork();
    if(child_process == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); }

    /*----------------------- Child ----------------------*/
    if(child_process == 0)
    {
      fprintf(stderr,"CHILD PID: %d\n", getpid());
      sprintf(buffer, "%d", fd_pipe[0]);
      (void)execl("/usr/local/src/comedilib-0.7.16/local/ver5/broker_child"
                , "/usr/local/src/comedilib-0.7.16/local/ver5/broker_child"
                , buffer, (char *)0);
      exit(EXIT_FAILURE);
    }
    else /*------------------ Parent ---------------------*/
    {
      log_broker_pid();
      (void) signal(SIGALRM, terminate);
      if (!(rdbuf = malloc(n_rdbuf))) {
                fprintf(stderr, "Could not allocate read buffer\n");
                exit(-1);
      }
      if (!(outbuf = malloc(n_outbuf))) {
                fprintf(stderr, "Could not allocate output buffer\n");
                exit(-1);
      }
      if (verbose) printf("buffers: %d read, %d outp\n", n_rdbuf, n_outbuf);
      total = 0;
      /*--------------------- While Loop Reading from Comedi Interface ------------------*/
      while(1)
      {

        ret=read(comedi_fileno(device),rdbuf,n_rdbuf);

        if(ret<0) {
                if(errno==EAGAIN) {
                        if (verbose) printf("waiting %d\n",period);
                        usleep(period);
                        continue;
                }
                comedi_perror("read perror");
                break;
        } else if(ret==0) {
                printf ("Unexpected EOF\n");
                exit(-1);
        }
        // here we have ret>0 :
        if (total+ret < n_outbuf) {
           for (i=0; i<ret; i++) 
           {
                   outbuf[total+i] = rdbuf[i];
           }
           total+=ret;
           if (verbose)
              printf("read and saved %d scans, total %d\n", ret/2/nchans,total/2/nchans);
        }
        else
        {
           for (i=0; total+i < n_outbuf; i++)
           {
                outbuf[total+i] = rdbuf[i];
           }
            
           // now send a data packet to pipe and file:
           if ((res = write(fd_pipe[1], outbuf, n_outbuf)) != n_outbuf)
           {
              fprintf(stderr,"\nError writing to the pipe.\n"); exit(EXIT_FAILURE);
           }
           if (fd_data) write(fd_data,outbuf,n_outbuf);
            
           total = ret - i;
           for (ii=i; ii<ret; ii++) 
           {
             outbuf[ii-i] = rdbuf[ii];
           }
           if (verbose)
           printf("read %d scans, print, remaining %d\n", ret/2/nchans,total/2/nchans);
        }

      } /* end of while loop */

      if(fd_pipe[1]) { fprintf(stderr,"Closing pipe: %s\n", fd_pipe[1]); close(fd_pipe[1]); }
      kill(child_process, SIGALRM);

    } /*-------- End of Parent Process -------*/
  }
 /*========================= End of PIPE Creation ===========================*/

  return 0;
}
/*---------------------------------------------------------------------------*/
void terminate(void)
{
  fprintf(stderr,"Received KILL Signal\n");
  kill(child_process, SIGALRM);
  fprintf(stderr,"Child PID: %d terminated\n", child_process);
  usleep(1000);
  fprintf(stderr,"File broker.pid removed\n");
  unlink("broker.pid");
  fprintf(stderr,"Broker PID: %d terminated\n", getpid());
  kill(getpid(), SIGKILL);
}
/*---------------------------------------------------------------------------*/
void log_broker_pid(void)
{
  FILE * fp;

        fprintf(stderr,"Broker PID: %d\n", getpid());
  if((fp = fopen("broker.pid", "w+")) == NULL)
  { fprintf(stderr,"Cannot open file.\n"); exit(1); }
  fprintf(fp, "%d\n", getpid());
  fclose(fp);
}
/*---------------------------------------------------------------------------*/
int set_real_time_priority(void)
{
struct sched_param schp;
    /*
     * set the process to real-time privs
     */
    memset(&schp, 0, sizeof(schp));
    schp.sched_priority = sched_get_priority_max(SCHED_FIFO);

    if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {
            perror("sched_setscheduler");
            return -1;
    }

     return 0;

}
/*---------------------------------------------------------------------------*/