Skip to content
Snippets Groups Projects
main.c 3.25 KiB
Newer Older
Patrick Robbe's avatar
Patrick Robbe committed
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "ecs.h"

static int flag_devnum = 0;
static int flag_barnum = -1;
static int flag_address = 0;
static uint32_t flag_addroff;
static int flag_write = 0;
static uint32_t flag_writeval;
static int flag_read = 0;

//ug`pcie40_ecs.synopsis`
// *pcie40_ecs* [-i _interface_] -b _bar_ -a _address_ -w _value_ _
// *pcie40_ecs* [-i _interface_] -b _bar_ -a _address_ -r
static void usage()
{
  fprintf(stderr, "usage: pcie40_ecs [options]\n");
  fprintf(stderr, "  -h    Print this message\n");
  fprintf(stderr, "  -i {} Interface number (default: 0)\n");
  fprintf(stderr, "  -b {} BAR number\n");
  fprintf(stderr, "  -a {} Register address\n");
  fprintf(stderr, "  -w {} Write value to register\n");
  fprintf(stderr, "  -r    Read register\n");
}

//ug`pcie40_ecs.description`
// Reads and writes PCIe40 BAR0 and BAR2 registers over PCI Express.

int main(int argc, char *argv[])
{
  while (argc > 1 && argv[1][0] == '-') {
    switch (argv[1][1]) {

      //ug`pcie40_ecs.options`interface
      // *-i* _interface_::
      // Bind to PCIe40 interface number _interface_. This is optional and by default the tool will bind to the first interface available (typically 0).
      case 'i':
        ++argv;
        --argc;
        flag_devnum = atoi(argv[1]);
        break;

      //ug`pcie40_ecs.options`bar
      // *-b* _bar_::
      // Access BAR number _bar_. Two PCI BARs are available:
      // * 0 for user code (includes registers for DAQ, TFC, SCA...)
      // * 2 for the common low-level interface
      case 'b':
        ++argv;
        --argc;
        flag_barnum = atoi(argv[1]);
        break;

      //ug`pcie40_ecs.options`address
      // *-a* _address_::
      // Address to use for BAR access. Can be in decimal, hexadecimal or any other format supported by *strtol(3)*.
      case 'a':
        ++argv;
        --argc;
        flag_address = 1;
        flag_addroff = strtol(argv[1], NULL, 0);
        break;

      //ug`pcie40_ecs.options`write
      // *-w* _value_::
      // Write 32-bit _value_ to register at the given address. Same input format considerations apply as for the *-a* option.
      case 'w':
        ++argv;
        --argc;
        flag_write = 1;
        flag_writeval = strtoul(argv[1], NULL, 0);
        break;

      //ug`pcie40_ecs.options`read
      // *-r*::
      // Read value of register at given address. Value is printed to stdout in hexadecimal format.
      case 'r':
        flag_read = 1;
        break;

      //ug`pcie40_ecs.options`help
      // *-h*::
      // Output short program synopsis and exit.
      default:
      case 'h':
        usage();
        exit(1);
        break;
    }
    --argc;
    ++argv;
  }
  //ug`pcie40_ecs.exit`
  // -1 is returned in case of access error or wrong command line options, 0 otherwise.
  if (!flag_address || flag_barnum < 0) {
    usage();
    exit(-1);
  }
  if (!flag_read && !flag_write) {
    printf("-r and -w are mutually exclusive\n");
    exit(-1);
  }

  uint32_t *regs;
  int ecs = p40_ecs_open(flag_devnum, flag_barnum, &regs);

  if (flag_write) {
    p40_ecs_w32(regs, flag_addroff, flag_writeval);
  } else if (flag_read) {
    uint32_t reg = p40_ecs_r32(regs, flag_addroff);
    printf("0x%08x", reg);
  }
  p40_ecs_close(ecs, regs);

  return 0;
}