HW/DAS/USBscopes/usbtm/bash/multiscope.c

#include "usbscope.h"
#include <string.h>
#include <math.h>

#define MAXDEV 4

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

struct devinfo {
  int addr;
  int fd;
  float ran;
  int ran_code;
  int ran_prec;
  float raw_offset;
  float dac_scale;
  int trig_offset;
  char fnread[PATH_MAX];
  char fnwrite[PATH_MAX];
};


int detect_init(struct devinfo *di, int devs, int master) {
  int i, ret;

  for(i = 0; i < devs; i++) {
    usbtm_set_trig_master(di[i].fd, 0);
    usbtm_set_detect_line(di[i].fd, 0, 1);
  }

  usbtm_set_detect_line(di[master].fd, 0, 1);
  usbtm_get_detect_line(di[master].fd, &ret);
  if(!ret) {
    fprintf(stderr, "Nektere z propojenych zarizeni neni pripojeno na USB!\n");
    return 0;
  }
  usbtm_set_detect_line(di[master].fd, 1, 0);

  for(i = 0; i < devs; i++) {
    if(i == master) continue;
    usbtm_set_detect_line(di[i].fd, 0, 1);
    usbtm_get_detect_line(di[i].fd, &ret);
    if(ret) {
      fprintf(stderr, "Nektere uvedene zarizeni neni propojeno s ostatnimi!\n");
      return 0;
    }
  }

  for(i = 0; i < devs; i++)
    if(!scope50_init_scope(di[i].fd, i==master,
          &di[i].raw_offset, &di[i].dac_scale, &di[i].trig_offset)) return 0;

  scope50_set_trig_master(di[master].fd, 1);

  return 1;
}


int parse_coupling(char *str) {
  int ret = -1;
  if(!strcasecmp(str, "ac")) ret = SCOPE50_COUPLING_AC;
  if(!strcasecmp(str, "dc")) ret = SCOPE50_COUPLING_DC;
  return ret;
}

int parse_edge(char *str) {
  int ret = -1;
  if(*str == 'l') ret = SCOPE50_TRIG_TYPE_LESS;
  if(*str == 'g') ret = SCOPE50_TRIG_TYPE_GREATER;
  if(*str == 'u') ret = SCOPE50_TRIG_TYPE_EDGE_UP;
  if(*str == 'd') ret = SCOPE50_TRIG_TYPE_EDGE_DOWN;
  return ret;
}


int main(int argc, char *argv[]) {
  int opt, devs = 0, help = 0;
  struct devinfo di[MAXDEV];
  int len = 3072, freq = 1E7, pretrig = 0, real,
      coup = SCOPE50_COUPLING_DC, ttype = SCOPE50_TRIG_TYPE_EDGE_UP;
  int i, j, res;
  float thresh = 0, ran, rc, rp, defran = 3.0;
  int defranc = SCOPE50_RANGE_30V, defranp = 2;
  unsigned char data[4][3072];
  int master = 0;
  FILE *fcalib;

  while((opt = getopt(argc, argv, "d:mf:l:r:t:p:e:C:S:L:h?")) != -1)
    switch(opt) {
      case 'd':
        if(devs == MAXDEV) {
          help = 1;
          break;
        }
        di[devs].addr = atoi(optarg);
        di[devs].ran = defran;
        di[devs].ran_code = defranc;
        di[devs].ran_prec = defranp;
        di[devs].raw_offset = 0;
        di[devs].dac_scale = 0;
        di[devs].trig_offset = 0;
        di[devs].fnread[0] = 0;
        di[devs].fnwrite[0] = 0;
        devs++;
        break;
      case 'm':
        if(!devs) help = 1;
        else master = devs-1;
        break;
      case 'f':
        freq = (int)(atof(optarg));
        break;
      case 'l':
        len = atoi(optarg);
        break;
      case 't':
        thresh = atof(optarg);
        break;
      case 'p':
        pretrig = atoi(optarg);
        break;
      case 'e':
        ttype = parse_edge(optarg);
        break;
      case 'C':
        coup = parse_coupling(optarg);
        break;
      case 'r':
        ran = atof(optarg);
        if(ran > 0 && ran < 0.4) ran = 0.3, rc = SCOPE50_RANGE_3V, rp = 3;
        else if(ran > 0.4 && ran < 4) ran = 3, rc = SCOPE50_RANGE_30V, rp = 2;
        else if(ran > 4 && ran <= 300) ran = 30, rc = SCOPE50_RANGE_300V, rp = 1;
        else help = 1;
        if(!devs) defran = ran, defranc = rc, defranp = rp;
        else di[devs-1].ran = ran, di[devs-1].ran_code = rc, di[devs-1].ran_prec = rp;
        break;
      case 'S':
        if(!devs) {
          help = 1;
          break;
        }
        strcpy(di[devs-1].fnwrite, optarg);
        break;
      case 'L':
        if(!devs) {
          help = 1;
          break;
        }
        strcpy(di[devs-1].fnread, optarg);
        break;
      default:
        help = 1;
        break;
    }
  if(help || optind != argc || devs < 1 || len < 1 || len > 3072 ||
      fabs(thresh) > 0.9*di[0].ran || pretrig > len || ttype < 0 || coup < 0) {
    printf("Pouziti: %s [-f freq] [-p pretrig] [-t thresh] [-e edge]\n"
        "    [-l len] [-C coup] [-d dev] [-r ran] [-m] [-S|-L conf] [-d...\n"
        "  freq je pocet vzorku za vterinu: 25 - 5E7 (vychozi: 1E7).\n"
        "  pretrig je pocet vzorku v pameti pred spustenim triggeru.\n"
        "  thresh je prahove napeti triggeru ve voltech.\n"
        "  edge je zpusob detekce hrany: less/l, greater/g, up/u, down/d.\n"
        "  len je delka zaznamu: 1 - 3072 (vychozi: maximum).\n"
        "  dev je cislo zarizeni %sn, na ktere se pripojit.\n"
        "  ran je vertikalni rozsah kanalu: 0.3, 3 nebo 30 V (vych. 3).\n"
        "    Jestlize je uvedeno pred prvnim -d, urcuje vychozi hodnotu.\n"
        "  -m urcuje predchozi -d jako Trigger Master.\n"
        "  Volby -S/-L umoznuji ulozit / nacist kalibracni data pro\n"
        "    rychlejsi spusteni. Uvedte zvlast pro kazdy kanal.\n",
        argv[0], DEVNAME);
    return 0;
  }

  for(i = 0; i < devs; i++)
    if(!opendev(di[i].addr, &di[i].fd)) {
      fprintf(stderr, deverror(di[i].addr));
      return 1;
    }

  for(i = 0; i < devs; i++) {
    if(*di[i].fnread) {
      fcalib = fopen(di[i].fnread, "r");
      if(!fcalib) {
        fprintf(stderr,
            "Nepodarilo se otevrit soubor %s pro cteni kalibracnich dat.\n", di[i].fnread);
      } else {
        if(fscanf(fcalib, "%f %f %i", &di[i].raw_offset, &di[i].dac_scale, &di[i].trig_offset) < 3) {
          fprintf(stderr, "Neplatna kalibracni data.");
          di[i].raw_offset = di[i].dac_scale = di[i].trig_offset = 0;
        }
        fclose(fcalib);
      }
    }
  }

  if(!detect_init(di, devs, master)) {
    for(i = 0; i < devs; i++)
      closedev(di[i].addr, di[i].fd);
    return 1;
  }

  for(i = 0; i < devs; i++) {
    if(*di[i].fnwrite) {
      fcalib = fopen(di[i].fnwrite, "w");
      if(!fcalib) {
        fprintf(stderr,
            "Nepodarilo se otevrit soubor %s pro ulozeni kalibracnich dat.\n", di[i].fnwrite);
      } else {
        fprintf(fcalib, "%f %f %i", di[i].raw_offset, di[i].dac_scale, di[i].trig_offset);
        fclose(fcalib);
      }
    }
  }

  for(i = 0; i < devs; i++) {
    scope50_setup_front_end(di[i].fd, di[i].ran_code, coup, 0);
    scope50_set_sample_frequency(di[i].fd, freq, &real);
    if(real != freq) fprintf(stderr, "Skutecna vzorkovaci frekvence: %i\n", real);
    scope50_set_offset(di[i].fd, 0, NULL);
    scope50_set_norm_trig(di[i].fd, 1);
  }

  scope50_set_trig_thresh(di[master].fd, thresh*100.0/di[master].ran);
  scope50_set_trig_type(di[master].fd, ttype);
  scope50_set_pretrig_depth(pretrig);
  scope50_set_trig_master(di[master].fd, 1);

  for(i = 0; i < devs; i++)
    if(i != master)
      scope50_acquisition_start(di[i].fd);
  scope50_acquisition_start(di[master].fd);

  do {
    if(!scope50_get_acquisition_state(di[master].fd, &res)) return 1;
    if(res) usleep(100);
  } while(res);

  for(i = 0; i < devs; i++)
    scope50_get_buffer_blocks_raw(di[i].fd, data[i], 6);

  for(j = 0; j < len; j++) {
    for(i = 0; i < devs; i++) {
      if(i) printf("\t");
      printf("%.*f", di[i].ran_prec, (data[i][j]/255.0 - 0.5)*2*di[i].ran);
    }
    printf("\n");
  }
  fflush(stdout);

  for(i = 0; i < devs; i++)
    closedev(di[i].addr, di[i].fd);

  return 0;
}