static pwr_tStatus IoAgentInit(io_tCtx ctx, io_sAgent* ap)
{
  int sts;
  io_sLocalHilscher_cifX_PnController* local;
  pwr_sClass_Hilscher_cifX_PnController* op
      = (pwr_sClass_Hilscher_cifX_PnController*)ap->op;

  local = (io_sLocalHilscher_cifX_PnController*)calloc(
      1, sizeof(io_sLocalHilscher_cifX_PnController));
  ap->Local = local;

  strcpy(op->ErrorStr, "");
  op->Status = 0;

  if (driver == 0) {
    struct CIFX_LINUX_INIT init;

    memset(&init, 0, sizeof(init));
    init.init_options = CIFX_DRIVER_INIT_AUTOSCAN;
    init.trace_level = 255;

    sts = cifXDriverInit(&init);
    if (!status_check(op, ap, sts, "cifXDriverInit"))
      return IO__INITFAIL;

    sts = xDriverOpen(&driver);
    if (!status_check(op, ap, sts, "xDriverOpen"))
      return IO__INITFAIL;
  }

  // Find the board
  unsigned long board = 0;
  BOARD_INFORMATION boardinfo;
  boardinfo.lBoardError = 0;
  int found = 0;

  while (xDriverEnumBoards(driver, board, sizeof(boardinfo), &boardinfo)
      == CIFX_NO_ERROR) {
    if (str_NoCaseStrcmp(boardinfo.abBoardAlias, op->Alias) == 0) {
      found = 1;
      break;
    }
    board++;
  }
  if (!found) {
    sprintf(op->ErrorStr, "Board with alias \"%s\" not found", op->Alias);
    errh_Error("IO init %s, '%s'", ap->Name, op->ErrorStr);
    return IO__INITFAIL;
  }

  op->Diag.DeviceNumber = boardinfo.tSystemInfo.ulDeviceNumber;
  op->Diag.SerialNumber = boardinfo.tSystemInfo.ulSerialNumber;
  op->Diag.SystemError = boardinfo.ulSystemError;
  // op->Diag.VendorId = boardinfo.tSystemInfo.usManufacturer;

  local->channel = 0;

  local->chan = NULL;

  sts = xChannelOpen(NULL, (char*)CIFX_DEV, local->channel, &local->chan);
  if (!status_check(op, ap, sts, "xChannelOpen"))
    return IO__INITFAIL;

  uint32_t state;
  strcpy(op->ErrorStr, "Device host state not ready");
  for (;;) {
    sts = xChannelHostState(local->chan, CIFX_HOST_STATE_READY, &state, 100);
    if (sts != CIFX_DEV_NOT_READY)
      break;
    sleep(1);
  }
  strcpy(op->ErrorStr, "");

  sts = xChannelReset(local->chan, CIFX_SYSTEMSTART, 2000);
  if (sts != CIFX_NO_ERROR) {
    printf("xChannelReset: 0x%08x\n", sts);
  }

  for (;;) {
    sts = xChannelHostState(local->chan, CIFX_HOST_STATE_READY, &state, 100);
    if (sts != CIFX_DEV_NOT_READY)
      break;
    sleep(1);
  }

  CHANNEL_INFORMATION channelinfo = { { 0 } };
  sts = xDriverEnumChannels(
      driver, board, local->channel, sizeof(channelinfo), &channelinfo);
  if (sts == CIFX_NO_ERROR) {
    strncpy(op->Diag.FirmwareName, (char*)channelinfo.abFWName,
        sizeof(op->Diag.FirmwareName));
    snprintf(op->Diag.FirmwareVersion, sizeof(op->Diag.FirmwareVersion),
        "%u.%u.%u-%u (%4u-%02hu-%02hu)", channelinfo.usFWMajor,
        channelinfo.usFWMinor, channelinfo.usFWBuild, channelinfo.usFWRevision,
        channelinfo.usFWYear, channelinfo.bFWMonth, channelinfo.bFWDay);
  }

  RCX_LOCK_UNLOCK_CONFIG_REQ_T unlock = { { 0 } };
  RCX_LOCK_UNLOCK_CONFIG_CNF_T unlock_cnf = { { 0 } };

  unlock.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  unlock.tHead.ulLen = HOST_TO_LE32(sizeof(unlock.tData));
  unlock.tHead.ulCmd = HOST_TO_LE32(RCX_LOCK_UNLOCK_CONFIG_REQ);
  unlock.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  unlock.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
  unlock.tData.ulParam = 2; // Unlock

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&unlock, 10);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(
      local->chan, sizeof(unlock_cnf), (CIFX_PACKET*)&unlock_cnf, 20000);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, unlock_cnf.tHead.ulCmd, RCX_LOCK_UNLOCK_CONFIG_CNF)
      || !status_check(op, ap, unlock_cnf.tHead.ulSta, "Unlock channel"))
    return IO__INITFAIL;

  t_addr ipaddress;
  t_addr subnetmask;
  int num;

  num = sscanf(op->IP_Address, "%hhu.%hhu.%hhu.%hhu", &ipaddress.b[3],
      &ipaddress.b[2], &ipaddress.b[1], &ipaddress.b[0]);
  if (num != 4) {
    sprintf(op->ErrorStr, "IP Address syntax error, %s", ap->Name);
    return IO__INITFAIL;
  }
  num = sscanf(op->SubnetMask, "%hhu.%hhu.%hhu.%hhu", &subnetmask.b[3],
      &subnetmask.b[2], &subnetmask.b[1], &subnetmask.b[0]);
  if (num != 4) {
    sprintf(op->ErrorStr, "SubnetMask syntax error, %s", ap->Name);
    return IO__INITFAIL;
  }

  PNM_APCFG_CFG_PNM_REQ_T pnm_config = { { 0 } };
  PNM_APCFG_CFG_PNM_CNF_T pnm_config_cnf;

  memset(&pnm_config, 0, sizeof(pnm_config));
  memset(&pnm_config_cnf, 0, sizeof(pnm_config_cnf));

  pnm_config.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  pnm_config.tHead.ulDestId = 0;
  pnm_config.tHead.ulLen = HOST_TO_LE32(sizeof(pnm_config.tData));
  pnm_config.tHead.ulId = HOST_TO_LE32(msg_id++);
  pnm_config.tHead.ulCmd = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_PNM_REQ);
  pnm_config.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  pnm_config.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
  pnm_config.tData.tSubHead.ulTrCntrId = 0;
  pnm_config.tData.tSubHead.ulTrDevId = 0;
  pnm_config.tData.tSubHead.ulTrApId = 0;
  pnm_config.tData.tSubHead.ulTrModId = 0;
  pnm_config.tData.tSubHead.ulTrSubModId = 0;
  pnm_config.tData.tSubHead.ulTrIdCnt = 1;
  pnm_config.tData.atData[0].ulTrId = 1;
  pnm_config.tData.atData[0].ulSystemFlags = PNM_APCFG_STARTMODE_APPLICATION;
  pnm_config.tData.atData[0].ulWdgTime = 1000;
  strncpy((char*)pnm_config.tData.atData[0].abTypeOfStation, op->DeviceType,
      sizeof(pnm_config.tData.atData[0].abTypeOfStation));
  pnm_config.tData.atData[0].usTypeOfStationLen
      = strlen((char*)pnm_config.tData.atData[0].abTypeOfStation);
  strncpy((char*)pnm_config.tData.atData[0].abNameOfStation, op->DeviceName,
      sizeof(pnm_config.tData.atData[0].abNameOfStation));
  pnm_config.tData.atData[0].usNameOfStationLen
      = strlen((char*)pnm_config.tData.atData[0].abNameOfStation);
  pnm_config.tData.atData[0].usVendorID
      = 0x011E; /* Hilscher Profinet VendorID */
  pnm_config.tData.atData[0].usDeviceID
      = 0x0203; /* Hilscher cifX DeviceID for IO-Controller */
  pnm_config.tData.atData[0].ulIPAddr = ipaddress.m;
  pnm_config.tData.atData[0].ulNetmask = subnetmask.m;
  pnm_config.tData.atData[0].ulGateway = 0;
  pnm_config.tData.atData[0].ulIPFlags = 0;
  // These are in the 'EXT' message
  // pnm_config.tData.atData[0].usMAUTypePort0 = PNM_APCFG_PNM_MAUTYPE_AUTO;
  // pnm_config.tData.atData[0].usMAUTypePort1 = PNM_APCFG_PNM_MAUTYPE_AUTO;
  // pnm_config.tData.atData[0].ulStructVersion =
  // PNM_APCFG_CFG_PNM_STRUCT_VERS_1;

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&pnm_config, 10);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(
      local->chan, sizeof(pnm_config_cnf), (CIFX_PACKET*)&pnm_config_cnf, 20);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, pnm_config_cnf.tHead.ulCmd,
             PNM_APCTL_CMD_SET_CONFIG_PNM_CNF)
      || !status_check(op, ap, pnm_config_cnf.tHead.ulSta, "Controller Config"))
    return IO__INITFAIL;

  // Device loop

  int device = 0;

  int input_dpm_offset = 0;
  int output_dpm_offset = 0;
  int prev_input_dpm_offset = 0;
  int prev_output_dpm_offset = 0;
  io_sRack* rp;
  io_sCard* cp;

  int dev_cnt = 0;
  for (rp = ap->racklist; rp; rp = rp->next) {
    io_sPnRackLocal* rp_local;

    dev_cnt++;

    rp_local = (io_sPnRackLocal*)calloc(1, sizeof(io_sPnRackLocal));
    rp->Local = rp_local;

    rp_local->userdata = calloc(1, sizeof(cifx_sDeviceUserData));

    for (cp = rp->cardlist; cp; cp = cp->next)
      cp->Local = calloc(1, sizeof(io_sPnCardLocal));

    GsdmlDeviceData* dev_data;
    dev_data = new GsdmlDeviceData;
    pwr_tFileName fname;

    sprintf(fname, "$pwrp_load/pwr_pn_%s.xml",
        cdh_ObjidToFnString(NULL, rp->Objid));
    dcli_translate_filename(fname, fname);

    sts = dev_data->read(fname);
    if (EVEN(sts)) {
      snprintf(op->ErrorStr, sizeof(op->ErrorStr),
          "Missing device xml file, %s", rp->Name);
      return IO__INITFAIL;
    }

    ((cifx_sDeviceUserData*)rp_local->userdata)->dev_data = dev_data;
  }

  // PNM_IOD

  PNM_APCFG_CFG_IOD_REQ_T* iod_config = (PNM_APCFG_CFG_IOD_REQ_T*)calloc(1,
      sizeof(*iod_config) + (dev_cnt - 1) * sizeof(iod_config->tData.atData));
  PNM_APCFG_CFG_IOD_CNF_T iod_config_cnf = { { 0 } };

  iod_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  iod_config->tHead.ulLen = HOST_TO_LE32(sizeof(iod_config->tData)
      + (dev_cnt - 1) * sizeof(iod_config->tData.atData));
  iod_config->tHead.ulId = HOST_TO_LE32(msg_id++);
  iod_config->tHead.ulCmd = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_REQ);
  iod_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  iod_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
  iod_config->tData.tSubHead.ulTrCntrId = 1;
  iod_config->tData.tSubHead.ulTrDevId = 0;
  iod_config->tData.tSubHead.ulTrApId = 0;
  iod_config->tData.tSubHead.ulTrModId = 0;
  iod_config->tData.tSubHead.ulTrSubModId = 0;
  iod_config->tData.tSubHead.ulTrIdCnt = dev_cnt;

  device = 0;
  for (rp = ap->racklist; rp; rp = rp->next) {
    t_addr ipaddress;
    t_addr subnetmask;

    io_sPnRackLocal* rp_local = (io_sPnRackLocal*)rp->Local;
    GsdmlDeviceData* dev_data
        = ((cifx_sDeviceUserData*)rp_local->userdata)->dev_data;

    sscanf(dev_data->ip_address, "%hhu.%hhu.%hhu.%hhu", &ipaddress.b[3],
        &ipaddress.b[2], &ipaddress.b[1], &ipaddress.b[0]);
    sscanf(dev_data->subnet_mask, "%hhu.%hhu.%hhu.%hhu", &subnetmask.b[3],
        &subnetmask.b[2], &subnetmask.b[1], &subnetmask.b[0]);

    iod_config->tData.atData[device].ulTrId = device + 1;
    iod_config->tData.atData[device].ulFlags = PNM_APCFG_IOD_FLAG_IOD_ACTIVE;
    strncpy((char*)iod_config->tData.atData[device].abNameOfStation,
        dev_data->device_name,
        sizeof(iod_config->tData.atData[device].abNameOfStation));
    iod_config->tData.atData[device].usNameOfStationLen
        = strlen((char*)iod_config->tData.atData[device].abNameOfStation);
    iod_config->tData.atData[device].usVendorID = dev_data->vendor_id;
    iod_config->tData.atData[device].usDeviceID = dev_data->device_id;
    iod_config->tData.atData[device].ulIPAddr = ipaddress.m;
    iod_config->tData.atData[device].ulNetworkMask = subnetmask.m;
    iod_config->tData.atData[device].ulGatewayAddr = 0;
    iod_config->tData.atData[device].ulArUuidData1 = device + 1;
    iod_config->tData.atData[device].usArUuidData2 = device + 1;
    iod_config->tData.atData[device].usArUuidData3 = device + 1;
    iod_config->tData.atData[device].usARType = PNIO_API_AR_TYPE_SINGLE;
    iod_config->tData.atData[device].ulARProp = PNIO_API_AR_PROP_SUPERVISOR_NONE
        | PNIO_API_AR_PROP_STATE_PRIMARY | PNIO_API_AR_PROP_SINGLE_AR | (1 << 4)
        | (1 << 5);
    iod_config->tData.atData[device].usAlarmCRType = PNIO_API_ALCR_TYPE_ALARM;
    iod_config->tData.atData[device].ulAlarmCRProp
        = PNIO_API_ALCR_PROP_PRIO_DEFAULT;
    iod_config->tData.atData[device].usAlarmCRVLANID = 0;
    iod_config->tData.atData[device].ulIPFlags = 0;
    iod_config->tData.atData[device].usRTATimeoutFact = 1;
    iod_config->tData.atData[device].usRTARetries = PNIO_API_RTA_RETRIES_MIN;
    iod_config->tData.atData[device].usObjUUIDInst = dev_data->instance;

    device++;
  }

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)iod_config, 10);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(
      local->chan, sizeof(iod_config_cnf), (CIFX_PACKET*)&iod_config_cnf, 20);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, iod_config_cnf.tHead.ulCmd,
             PNM_APCTL_CMD_SET_CONFIG_IOD_CNF)
      || !status_check(op, ap, pnm_config_cnf.tHead.ulSta, "Device Config"))
    return IO__INITFAIL;

  device = 0;
  for (rp = ap->racklist; rp; rp = rp->next) {
    // Read device xml-file
    io_sPnRackLocal* rp_local = (io_sPnRackLocal*)rp->Local;
    GsdmlDeviceData* dev_data
        = ((cifx_sDeviceUserData*)rp_local->userdata)->dev_data;

    unsigned char macaddr[6];

    // PNM_IOCR

    // Calculate data length
    unsigned int io_input_length = 0;
    unsigned int io_output_length = 0;
    unsigned int io_iocr_input_length = 0;
    unsigned int io_iocr_output_length = 0;

    for (unsigned int i = 0; i < dev_data->slot_data.size(); i++) {
      for (unsigned int j = 0; j < dev_data->slot_data[i]->subslot_data.size();
           j++) {
        if (dev_data->slot_data[i]->subslot_data[j]->io_input_length > 0) {
          io_input_length
              += dev_data->slot_data[i]->subslot_data[j]->io_input_length + 1;
          io_iocr_input_length += 1;
        }
        if (dev_data->slot_data[i]->subslot_data[j]->io_output_length > 0) {
          io_output_length
              += dev_data->slot_data[i]->subslot_data[j]->io_output_length + 1;
          io_iocr_output_length += 1;
        }
        if (dev_data->slot_data[i]->subslot_data[j]->io_input_length == 0
            && dev_data->slot_data[i]->subslot_data[j]->io_output_length == 0) {
          io_input_length += 1;
          io_iocr_input_length += 1;
        }
      }
    }

    PNM_APCFG_CFG_IOCR_REQ_T* iocr_config = (PNM_APCFG_CFG_IOCR_REQ_T*)calloc(
        1, sizeof(*iocr_config) + sizeof(iocr_config->tData.atData));
    PNM_APCFG_CFG_IOCR_CNF_T iocr_config_cnf = { { 0 } };

    sscanf(dev_data->mac_address, "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
        &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
        &macaddr[5]);

    iocr_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
    iocr_config->tHead.ulLen = HOST_TO_LE32(
        sizeof(iocr_config->tData) + sizeof(iocr_config->tData.atData));
    iocr_config->tHead.ulId = HOST_TO_LE32(msg_id++);
    iocr_config->tHead.ulCmd
        = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_IOCR_REQ);
    iocr_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
    iocr_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
    iocr_config->tData.tSubHead.ulTrCntrId = 1;
    iocr_config->tData.tSubHead.ulTrDevId = device + 1;
    iocr_config->tData.tSubHead.ulTrApId = 0;
    iocr_config->tData.tSubHead.ulTrModId = 0;
    iocr_config->tData.tSubHead.ulTrSubModId = 0;
    iocr_config->tData.tSubHead.ulTrIdCnt = 2;
    for (int i = 0; i < 2; i++) {
      iocr_config->tData.atData[i].ulTrId = i + 1;
      iocr_config->tData.atData[i].usType
          = dev_data->iocr_data[i ? 0 : 1]->type;
      iocr_config->tData.atData[i].usVLANID = 0;
      iocr_config->tData.atData[i].ulProp = PNIO_API_IOCR_PROP_RTCLASS_DATA1;
      // strncpy( (char *)iocr_config->tData.atData[i].abMcastMACAddr, (char
      // *)macaddr,
      //	     sizeof(iocr_config->tData.atData[i].abMcastMACAddr));
      memset((char*)iocr_config->tData.atData[i].abMcastMACAddr, 0,
          sizeof(iocr_config->tData.atData[i].abMcastMACAddr));
      if (iocr_config->tData.atData[i].usType == 1)
        iocr_config->tData.atData[i].usDataLen
            = io_input_length + io_iocr_output_length;
      else
        iocr_config->tData.atData[i].usDataLen
            = io_output_length + io_iocr_input_length;
      iocr_config->tData.atData[i].usSendClockFact
          = dev_data->iocr_data[i ? 0 : 1]->send_clock_factor;
      iocr_config->tData.atData[i].usReductRatio
          = dev_data->iocr_data[i ? 0 : 1]->reduction_ratio;
      iocr_config->tData.atData[i].usPhase
          = dev_data->iocr_data[i ? 0 : 1]->phase;
      iocr_config->tData.atData[i].usSequ = 0;
      iocr_config->tData.atData[i].ulFrameSendOffs
          = PNIO_API_FRAME_SEND_OFFSET_DEFAULT;
      iocr_config->tData.atData[i].usWatchdogFact
          = PNIO_API_CYCLIC_WATCHDOG_DEFAULT;
      iocr_config->tData.atData[i].usDataHoldFact
          = PNIO_API_CYCLIC_DATAHOLD_DEFAULT;
    }

    sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)iocr_config, 10);
    if (!status_check(op, ap, sts, "xChannelPutPacket"))
      return IO__INITFAIL;

    sts = xChannelGetPacket(local->chan, sizeof(iocr_config_cnf),
        (CIFX_PACKET*)&iocr_config_cnf, 20);
    if (!status_check(op, ap, sts, "xChannelGetPacket")
        || !cmd_check(op, ap, iocr_config_cnf.tHead.ulCmd,
               PNM_APCTL_CMD_SET_CONFIG_IOD_IOCR_CNF)
        || !status_check(op, ap, pnm_config_cnf.tHead.ulSta, "IOCR Config"))
      return IO__INITFAIL;

    free(iocr_config);

    // PNM_IOD_AP

    PNM_APCFG_CFG_AP_REQ_T ap_config = { { 0 } };
    PNM_APCFG_CFG_AP_CNF_T ap_config_cnf = { { 0 } };

    ap_config.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
    ap_config.tHead.ulLen = HOST_TO_LE32(sizeof(ap_config.tData));
    ap_config.tHead.ulId = HOST_TO_LE32(msg_id++);
    ap_config.tHead.ulCmd = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_AP_REQ);
    ap_config.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
    ap_config.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
    ap_config.tData.tSubHead.ulTrCntrId = 1;
    ap_config.tData.tSubHead.ulTrDevId = device + 1;
    ap_config.tData.tSubHead.ulTrApId = 0;
    ap_config.tData.tSubHead.ulTrModId = 0;
    ap_config.tData.tSubHead.ulTrSubModId = 0;
    ap_config.tData.tSubHead.ulTrIdCnt = 1;
    ap_config.tData.atData[0].ulTrId = 1;
    ap_config.tData.atData[0].ulAPI = 0;

    sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&ap_config, 10);
    if (!status_check(op, ap, sts, "xChannelPutPacket"))
      return IO__INITFAIL;

    sts = xChannelGetPacket(
        local->chan, sizeof(ap_config_cnf), (CIFX_PACKET*)&ap_config_cnf, 20);
    if (!status_check(op, ap, sts, "xChannelGetPacket")
        || !cmd_check(op, ap, ap_config_cnf.tHead.ulCmd,
               PNM_APCTL_CMD_SET_CONFIG_IOD_AP_CNF)
        || !status_check(
               op, ap, ap_config_cnf.tHead.ulSta, "Application Process"))
      return IO__INITFAIL;

    // PNM_MODULE

    // Check number of configured slots
    int slots = 0;
    for (unsigned int i = 0; i < dev_data->slot_data.size(); i++) {
      if (dev_data->slot_data[i]->module_ident_number == 0)
        break;
      slots++;
    }

    PNM_APCFG_CFG_MODULE_REQ_T* module_config
        = (PNM_APCFG_CFG_MODULE_REQ_T*)calloc(1, sizeof(*module_config)
                + (slots - 1) * sizeof(module_config->tData.atData));
    PNM_APCFG_CFG_MODULE_CNF_T module_config_cnf = { { 0 } };

    module_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
    module_config->tHead.ulLen = HOST_TO_LE32(sizeof(module_config->tData)
        + (slots - 1) * sizeof(module_config->tData.atData));
    module_config->tHead.ulId = HOST_TO_LE32(msg_id++);
    module_config->tHead.ulCmd
        = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_MODULE_REQ);
    module_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
    module_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
    module_config->tData.tSubHead.ulTrCntrId = 1;
    module_config->tData.tSubHead.ulTrDevId = device + 1;
    module_config->tData.tSubHead.ulTrApId = 1;
    module_config->tData.tSubHead.ulTrModId = 0;
    module_config->tData.tSubHead.ulTrSubModId = 0;
    module_config->tData.tSubHead.ulTrIdCnt = slots;
    for (int i = 0; i < slots; i++) {
      module_config->tData.atData[i].ulTrId = i + 1;
      module_config->tData.atData[i].ulModuleID
          = dev_data->slot_data[i]->module_ident_number;
      module_config->tData.atData[i].usModuleProp = 0;
      module_config->tData.atData[i].usSlotNumber
          = dev_data->slot_data[i]->slot_number;
    }

    sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)module_config, 10);
    if (!status_check(op, ap, sts, "xChannelPutPacket"))
      return IO__INITFAIL;

    sts = xChannelGetPacket(local->chan, sizeof(module_config_cnf),
        (CIFX_PACKET*)&module_config_cnf, 20);
    if (!status_check(op, ap, sts, "xChannelGetPacket")
        || !cmd_check(op, ap, module_config_cnf.tHead.ulCmd,
               PNM_APCTL_CMD_SET_CONFIG_IOD_MODULE_CNF)
        || !status_check(
               op, ap, module_config_cnf.tHead.ulSta, "Module Config"))
      return IO__INITFAIL;

    free(module_config);

    // PNM_SUBMODULE

    for (int i = 0; i < slots; i++) {
      int subslots = dev_data->slot_data[i]->subslot_data.size();

      PNM_APCFG_CFG_SUBMODULE_REQ_T* submodule_config
          = (PNM_APCFG_CFG_SUBMODULE_REQ_T*)calloc(1, sizeof(*submodule_config)
                  + (subslots - 1) * sizeof(submodule_config->tData.atData));
      PNM_APCFG_CFG_SUBMODULE_CNF_T submodule_config_cnf = { { 0 } };

      submodule_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
      submodule_config->tHead.ulLen
          = HOST_TO_LE32(sizeof(submodule_config->tData)
              + (subslots - 1) * sizeof(submodule_config->tData.atData));
      submodule_config->tHead.ulId = HOST_TO_LE32(msg_id++);
      submodule_config->tHead.ulCmd
          = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_SUBMODULE_REQ);
      submodule_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
      submodule_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
      submodule_config->tData.tSubHead.ulTrCntrId = 1;
      submodule_config->tData.tSubHead.ulTrDevId = device + 1;
      submodule_config->tData.tSubHead.ulTrApId = 1;
      submodule_config->tData.tSubHead.ulTrModId = i + 1;
      submodule_config->tData.tSubHead.ulTrSubModId = 0;
      submodule_config->tData.tSubHead.ulTrIdCnt = subslots;
      for (int j = 0; j < subslots; j++) {
        submodule_config->tData.atData[j].ulTrId = j + 1;
        submodule_config->tData.atData[j].ulSubmoduleID
            = dev_data->slot_data[i]->subslot_data[j]->submodule_ident_number;
        submodule_config->tData.atData[j].usSubmoduleProp = 0;
        if (dev_data->slot_data[i]->subslot_data[j]->io_input_length > 0
            && dev_data->slot_data[i]->subslot_data[j]->io_output_length > 0)
          submodule_config->tData.atData[j].usSubmoduleProp
              = PNIO_API_SUBM_PROP_TYPE_BOTH;
        else if (dev_data->slot_data[i]->subslot_data[j]->io_input_length > 0)
          submodule_config->tData.atData[j].usSubmoduleProp
              = PNIO_API_SUBM_PROP_TYPE_INPUT;
        else if (dev_data->slot_data[i]->subslot_data[j]->io_output_length > 0)
          submodule_config->tData.atData[j].usSubmoduleProp
              = PNIO_API_SUBM_PROP_TYPE_OUTPUT;
        else
          submodule_config->tData.atData[j].usSubmoduleProp
              = PNIO_API_SUBM_PROP_TYPE_NONE;

        submodule_config->tData.atData[j].usSubslotNumber
            = dev_data->slot_data[i]->subslot_data[j]->subslot_number;
        // printf( "Submodule %d %d\n", i+1, j+1);
      }

      sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)submodule_config, 10);
      if (!status_check(op, ap, sts, "xChannelPutPacket"))
        return IO__INITFAIL;

      sts = xChannelGetPacket(local->chan, sizeof(submodule_config_cnf),
          (CIFX_PACKET*)&submodule_config_cnf, 20);
      if (!status_check(op, ap, sts, "xChannelGetPacket")
          || !cmd_check(op, ap, submodule_config_cnf.tHead.ulCmd,
                 PNM_APCTL_CMD_SET_CONFIG_IOD_SUBMODULE_CNF)
          || !status_check(
                 op, ap, submodule_config_cnf.tHead.ulSta, "Submodule Config"))
        return IO__INITFAIL;

      free(submodule_config);
    }

    // PNM_SUBMDESCR

    int input_frame_offset = 0;
    int output_frame_offset = 0;
    int input_iocs_frame_offset = io_output_length;
    int output_iocs_frame_offset = io_input_length;

    for (int i = 0; i < slots; i++) {
      int subslots = dev_data->slot_data[i]->subslot_data.size();
      int prev_slot_input_dpm_offset = input_dpm_offset;
      int prev_slot_output_dpm_offset = output_dpm_offset;

      for (int j = 0; j < subslots; j++) {
        int io_input_length
            = dev_data->slot_data[i]->subslot_data[j]->io_input_length;
        int io_output_length
            = dev_data->slot_data[i]->subslot_data[j]->io_output_length;

        int size = 1;
        if (io_input_length > 0 && io_output_length > 0)
          size = 2;

        PNM_APCFG_CFG_SUBMDESCR_REQ_T* submdescr_config
            = (PNM_APCFG_CFG_SUBMDESCR_REQ_T*)calloc(
                1, sizeof(*submdescr_config)
                    + (size - 1) * sizeof(submdescr_config->tData.atData));
        PNM_APCFG_CFG_SUBMDESCR_CNF_T submdescr_config_cnf = { { 0 } };

        submdescr_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
        submdescr_config->tHead.ulLen
            = HOST_TO_LE32(sizeof(submdescr_config->tData)
                + (size - 1) * sizeof(submdescr_config->tData.atData));
        submdescr_config->tHead.ulId = HOST_TO_LE32(msg_id++);
        submdescr_config->tHead.ulCmd
            = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_SUBMDESCR_REQ);
        submdescr_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
        submdescr_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
        submdescr_config->tData.tSubHead.ulTrCntrId = 1;
        submdescr_config->tData.tSubHead.ulTrDevId = device + 1;
        submdescr_config->tData.tSubHead.ulTrApId = 1;
        submdescr_config->tData.tSubHead.ulTrModId = i + 1;
        submdescr_config->tData.tSubHead.ulTrSubModId = j + 1;
        submdescr_config->tData.tSubHead.ulTrIdCnt = size;
        for (int k = 0; k < size; k++) {
          submdescr_config->tData.atData[k].ulTrId = k + 1;
          if (io_input_length == 0 && io_output_length == 0) {
            submdescr_config->tData.atData[k].usDataDescr
                = PNIO_API_SUBMDESCR_DATA_DESCR_INPUT;
            submdescr_config->tData.atData[k].usSubmDataLen = 0;
            submdescr_config->tData.atData[k].usFrameOffs = input_frame_offset;
            submdescr_config->tData.atData[k].usIOCSFrameOffs
                = input_iocs_frame_offset;
            submdescr_config->tData.atData[k].ulIO_Block = 0;
            submdescr_config->tData.atData[k].ulDPM_Offset = 0;
            // printf( "%d %d None:   iocsoffs %d offs %d len %d\n", i+1, j+1,
            // input_iocs_frame_offset, input_frame_offset, io_input_length);
          } else if ((size == 1 && io_input_length > 0)
              || (size == 2 && k == 0)) {
            submdescr_config->tData.atData[k].usDataDescr
                = PNIO_API_SUBMDESCR_DATA_DESCR_INPUT;
            submdescr_config->tData.atData[k].usSubmDataLen = io_input_length;
            submdescr_config->tData.atData[k].usFrameOffs = input_frame_offset;
            submdescr_config->tData.atData[k].usIOCSFrameOffs
                = input_iocs_frame_offset;
            submdescr_config->tData.atData[k].ulIO_Block = 0;
            submdescr_config->tData.atData[k].ulDPM_Offset = input_dpm_offset;
            // printf( "%d %d Input:  iocsoffs %d offs %d len %d\n", i+1, j+1,
            // input_iocs_frame_offset, input_frame_offset, io_input_length);
          } else {
            submdescr_config->tData.atData[k].usDataDescr
                = PNIO_API_SUBMDESCR_DATA_DESCR_OUTPUT;
            submdescr_config->tData.atData[k].usSubmDataLen = io_output_length;
            submdescr_config->tData.atData[k].usFrameOffs = output_frame_offset;
            submdescr_config->tData.atData[k].usIOCSFrameOffs
                = output_iocs_frame_offset;
            submdescr_config->tData.atData[k].ulIO_Block = 0;
            submdescr_config->tData.atData[k].ulDPM_Offset = output_dpm_offset;
            // printf( "%d %d Output: iocsoffs %d offs %d len %d\n", i+1, j+1,
            // output_iocs_frame_offset, output_frame_offset, io_output_length);
          }
          submdescr_config->tData.atData[k].bIOPSLen = 1;
          submdescr_config->tData.atData[k].bIOCSLen = 1;
          submdescr_config->tData.atData[k].ulIOCRIdProd = 1;
          submdescr_config->tData.atData[k].ulIOCRIdCons = 2;
          submdescr_config->tData.atData[k].ulSignla_Attrib = 0;
        }

        sts = xChannelPutPacket(
            local->chan, (CIFX_PACKET*)submdescr_config, 10);
        if (!status_check(op, ap, sts, "xChannelPutPacket"))
          return IO__INITFAIL;

        sts = xChannelGetPacket(local->chan, sizeof(submdescr_config_cnf),
            (CIFX_PACKET*)&submdescr_config_cnf, 20);
        if (!status_check(op, ap, sts, "xChannelGetPacket")
            || !cmd_check(op, ap, submdescr_config_cnf.tHead.ulCmd,
                   PNM_APCTL_CMD_SET_CONFIG_IOD_SUBMDESCR_CNF)
            || !status_check(op, ap, submdescr_config_cnf.tHead.ulSta,
                   "Submodule Description"))
          return IO__INITFAIL;

        if (io_input_length > 0) {
          input_frame_offset += io_input_length + 1;
          input_iocs_frame_offset += 1;
          input_dpm_offset += io_input_length;
        }
        if (io_output_length > 0) {
          output_frame_offset += io_output_length + 1;
          output_iocs_frame_offset += 1;
          output_dpm_offset += io_output_length;
        }
        if (io_input_length == 0 && io_output_length == 0) {
          input_frame_offset += 1;
          input_iocs_frame_offset += 1;
        }

        free(submdescr_config);
      }

      if (i > 0) {
        // First slot is the device and has no card
        if (i == 1)
          cp = rp->cardlist;
        else
          cp = cp->next;

        if (!cp) {
          snprintf(op->ErrorStr, sizeof(op->ErrorStr),
              "Module config mismatch in xml-file, %s", rp->Name);
          errh_Error("IO init %s, '%s'", ap->Name, op->ErrorStr);
          return IO__INITFAIL;
        }

        io_sPnCardLocal* cp_local = (io_sPnCardLocal*)cp->Local;

        cp_local->input_area_size
            = input_dpm_offset - prev_slot_input_dpm_offset;
        cp_local->output_area_size
            = output_dpm_offset - prev_slot_output_dpm_offset;
      }
      prev_slot_input_dpm_offset = input_dpm_offset;
      prev_slot_output_dpm_offset = output_dpm_offset;
    }

    rp_local->bytes_of_input = input_dpm_offset - prev_input_dpm_offset;
    rp_local->bytes_of_output = output_dpm_offset - prev_output_dpm_offset;
    prev_input_dpm_offset = input_dpm_offset;
    prev_output_dpm_offset = output_dpm_offset;

    // PNM_RECORD

    for (int i = 0; i < slots; i++) {
      int subslots = dev_data->slot_data[i]->subslot_data.size();

      for (int j = 0; j < subslots; j++) {
        int records
            = dev_data->slot_data[i]->subslot_data[j]->data_record.size();

        if (!records)
          continue;

        int size = sizeof(PNM_APCFG_CFG_RECORD_REQ_T)
            + (records - 1) * (sizeof(PNM_APCFG_CFG_RECORD_DATA_T) - 1);
        for (int k = 0; k < records; k++)
          size += dev_data->slot_data[i]
                      ->subslot_data[j]
                      ->data_record[k]
                      ->data_length;

        PNM_APCFG_CFG_RECORD_REQ_T* record_config
            = (PNM_APCFG_CFG_RECORD_REQ_T*)calloc(1, size);
        PNM_APCFG_CFG_RECORD_CNF_T record_config_cnf = { { 0 } };

        record_config->tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
        record_config->tHead.ulLen = HOST_TO_LE32(size);
        record_config->tHead.ulId = HOST_TO_LE32(msg_id++);
        record_config->tHead.ulCmd
            = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_IOD_RECDATA_REQ);
        record_config->tHead.ulSrc = HOST_TO_LE32(PN_SRC);
        record_config->tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
        record_config->tData.tSubHead.ulTrCntrId = 1;
        record_config->tData.tSubHead.ulTrDevId = device + 1;
        record_config->tData.tSubHead.ulTrApId = 1;
        record_config->tData.tSubHead.ulTrModId = i + 1;
        record_config->tData.tSubHead.ulTrSubModId = j + 1;
        record_config->tData.tSubHead.ulTrIdCnt = records;

        PNM_APCFG_CFG_RECORD_DATA_T* rp = &record_config->tData.tRecord;
        for (int k = 0; k < records; k++) {
          rp->ulTrId = k + 1;
          rp->usIndex = k + 1;
          rp->ulDataLen = dev_data->slot_data[i]
                              ->subslot_data[j]
                              ->data_record[k]
                              ->data_length;
          memcpy(rp->abRecordData,
              dev_data->slot_data[i]->subslot_data[j]->data_record[k]->data,
              rp->ulDataLen);

          rp = (PNM_APCFG_CFG_RECORD_DATA_T*)((char*)rp + sizeof(*rp)
              + rp->ulDataLen - 1);
        }

        sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)record_config, 10);
        if (!status_check(op, ap, sts, "xChannelPutPacket"))
          return IO__INITFAIL;

        sts = xChannelGetPacket(local->chan, sizeof(record_config_cnf),
            (CIFX_PACKET*)&record_config_cnf, 20);
        if (!status_check(op, ap, sts, "xChannelGetPacket")
            || !cmd_check(op, ap, record_config_cnf.tHead.ulCmd,
                   PNM_APCTL_CMD_SET_CONFIG_IOD_RECDATA_CNF)
            || !status_check(
                   op, ap, record_config_cnf.tHead.ulSta, "Record Data"))
          return IO__INITFAIL;

        free(record_config);
      }
    }

    delete dev_data;
    ((cifx_sDeviceUserData*)rp_local->userdata)->dev_data = 0;

    device++;
  }

  // PNM_FIN

  PNM_APCFG_DWNL_FIN_REQ_T dwnl_fin_config = { { 0 } };
  PNM_APCFG_DWNL_FIN_CNF_T dwnl_fin_config_cnf = { { 0 } };

  dwnl_fin_config.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  dwnl_fin_config.tHead.ulLen = 0;
  dwnl_fin_config.tHead.ulId = HOST_TO_LE32(msg_id++);
  dwnl_fin_config.tHead.ulCmd
      = HOST_TO_LE32(PNM_APCTL_CMD_SET_CONFIG_DWNL_FIN_REQ);
  dwnl_fin_config.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  dwnl_fin_config.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&dwnl_fin_config, 10);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(local->chan, sizeof(dwnl_fin_config_cnf),
      (CIFX_PACKET*)&dwnl_fin_config_cnf, 20);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, dwnl_fin_config_cnf.tHead.ulCmd,
             PNM_APCTL_CMD_SET_CONFIG_DWNL_FIN_CNF)
      || !status_check(
             op, ap, dwnl_fin_config_cnf.tHead.ulSta, "Controller Config"))
    return IO__INITFAIL;

  // LOCK
  RCX_LOCK_UNLOCK_CONFIG_REQ_T lock = { { 0 } };
  RCX_LOCK_UNLOCK_CONFIG_CNF_T lock_cnf = { { 0 } };

  lock.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  lock.tHead.ulLen = HOST_TO_LE32(sizeof(lock.tData));
  lock.tHead.ulCmd = HOST_TO_LE32(RCX_LOCK_UNLOCK_CONFIG_REQ);
  lock.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  lock.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
  lock.tData.ulParam = 1; // Lock

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&lock, 10);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(
      local->chan, sizeof(lock_cnf), (CIFX_PACKET*)&lock_cnf, 20);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, lock_cnf.tHead.ulCmd, RCX_LOCK_UNLOCK_CONFIG_CNF)
      || !status_check(op, ap, lock_cnf.tHead.ulSta, "Unlock channel"))
    return IO__INITFAIL;

  // Register application
  RCX_REGISTER_APP_REQ_T regapp = { { 0 } };
  RCX_REGISTER_APP_CNF_T regapp_cnf = { { 0 } };

  regapp.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
  regapp.tHead.ulLen = 0;
  regapp.tHead.ulCmd = HOST_TO_LE32(RCX_REGISTER_APP_REQ);
  regapp.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
  regapp.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);

  sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&regapp, 1000);
  if (!status_check(op, ap, sts, "xChannelPutPacket"))
    return IO__INITFAIL;

  sts = xChannelGetPacket(
      local->chan, sizeof(regapp_cnf), (CIFX_PACKET*)&regapp_cnf, 10000);
  if (!status_check(op, ap, sts, "xChannelGetPacket")
      || !cmd_check(op, ap, regapp_cnf.tHead.ulCmd, RCX_REGISTER_APP_CNF)
      || !status_check(op, ap, regapp_cnf.tHead.ulSta, "Register Application"))
    return IO__INITFAIL;

  // Create input/output area
  local->input_area_size = input_dpm_offset;
  local->output_area_size = output_dpm_offset;

  local->input_area = calloc(1, MAX(local->input_area_size, 4));
  local->output_area = calloc(1, MAX(local->output_area_size, 4));

  int input_offset = 0;
  int output_offset = 0;
  for (rp = ap->racklist; rp; rp = rp->next) {
    io_sPnRackLocal* rp_local = (io_sPnRackLocal*)rp->Local;

    rp_local->inputs = (unsigned char*)local->input_area + input_offset;
    rp_local->outputs = (unsigned char*)local->output_area + output_offset;

    int slot_input_offset = input_offset;
    int slot_output_offset = output_offset;
    for (cp = rp->cardlist; cp; cp = cp->next) {
      io_sPnCardLocal* cp_local = (io_sPnCardLocal*)cp->Local;

      cp_local->input_area
          = (unsigned char*)local->input_area + slot_input_offset;
      cp_local->output_area
          = (unsigned char*)local->output_area + slot_output_offset;
      slot_input_offset += cp_local->input_area_size;
      slot_output_offset += cp_local->output_area_size;
    }
    input_offset += rp_local->bytes_of_input;
    output_offset += rp_local->bytes_of_output;

    // Set OK status on device
    ((pwr_sClass_PnDevice*)rp->op)->Status = PB__NORMAL;
    ((pwr_sClass_PnDevice*)rp->op)->State = pwr_ePnDeviceStateEnum_Connected;
  }

  for (;;) {
    sts = xChannelHostState(local->chan, CIFX_HOST_STATE_READY, &state, 100);
    if (sts != CIFX_DEV_NOT_RUNNING)
      break;
    sleep(1);
  }

  sts = xChannelHostState(local->chan, CIFX_HOST_STATE_READ, &state, 0);
  // printf( "Host state: %d\n", state);

  sts = xChannelBusState(local->chan, CIFX_BUS_STATE_GETSTATE, &state, 0);
  // printf( "Bus state: %d\n", state);

  sts = xChannelBusState(
      local->chan, CIFX_BUS_STATE_ON, &state, 5000 /* 20000 */);
  // printf( "Set bus state: 0x%08x\n", sts);

  sts = xChannelBusState(local->chan, CIFX_BUS_STATE_GETSTATE, &state, 0);
  // printf( "Bus state: %d\n", state);

  // It takes ~20 s to get COM-flag
  local->dev_init = 1;
  local->dev_init_limit = (unsigned int)(30.0 / ctx->ScanTime + 0.5);

  errh_Info("Init of Hilscher cifX Profinet Controller '%s'", ap->Name);
  return IO__SUCCESS;
}
Exemplo n.º 2
0
/* See libbladeRF's dc_cal_table.c for the packed table data format */
int calibrate_dc_gen_tbl(struct cli_state *s, bladerf_module module,
                         const char *filename, unsigned int f_low,
                         unsigned f_inc, unsigned int f_high)
{
    int retval, status;
    size_t off;
    struct bladerf_lms_dc_cals lms_dc_cals;
    unsigned int f;
    struct settings settings;
    bladerf_loopback loopback_backup;
    struct bladerf_image *image = NULL;

    const uint16_t magic = HOST_TO_LE16(0x1ab1);
    const uint32_t reserved = HOST_TO_LE32(0x00000000);
    const uint32_t tbl_version = HOST_TO_LE32(0x00000001);

    const size_t lms_data_size = 10; /* 10 uint8_t register values */

    const uint32_t n_frequencies = (f_high - f_low) / f_inc + 1;
    const uint32_t n_frequencies_le = HOST_TO_LE32(n_frequencies);

    const size_t entry_size = sizeof(uint32_t) +   /* Frequency */
                              2 * sizeof(int16_t); /* DC I and Q valus */

    const size_t table_size = n_frequencies * entry_size;

    const size_t data_size = sizeof(magic) + sizeof(reserved) +
                             sizeof(tbl_version) + sizeof(n_frequencies_le) +
                             lms_data_size + table_size;

    assert(data_size <= UINT_MAX);

    status = backup_and_update_settings(s->dev, module, &settings);
    if (status != 0) {
        return status;
    }

    status = bladerf_get_loopback(s->dev, &loopback_backup);
    if (status != 0) {
        return status;
    }

    status = bladerf_lms_get_dc_cals(s->dev, &lms_dc_cals);
    if (status != 0) {
        goto out;
    }

    if (module == BLADERF_MODULE_RX) {
        image = bladerf_alloc_image(BLADERF_IMAGE_TYPE_RX_DC_CAL,
                                    0xffffffff, (unsigned int) data_size);
    } else {
        image = bladerf_alloc_image(BLADERF_IMAGE_TYPE_TX_DC_CAL,
                                    0xffffffff, (unsigned int) data_size);
    }

    if (image == NULL) {
        status = BLADERF_ERR_MEM;
        goto out;
    }

    status = bladerf_get_serial(s->dev, image->serial);
    if (status != 0) {
        goto out;
    }

    if (module == BLADERF_MODULE_RX) {
        status = bladerf_set_loopback(s->dev, BLADERF_LB_NONE);
        if (status != 0) {
            goto out;
        }
    }

    off = 0;

    memcpy(&image->data[off], &magic, sizeof(magic));
    off += sizeof(magic);

    memcpy(&image->data[off], &reserved, sizeof(reserved));
    off += sizeof(reserved);

    memcpy(&image->data[off], &tbl_version, sizeof(tbl_version));
    off += sizeof(tbl_version);

    memcpy(&image->data[off], &n_frequencies_le, sizeof(n_frequencies_le));
    off += sizeof(n_frequencies_le);

    image->data[off++] = (uint8_t)lms_dc_cals.lpf_tuning;
    image->data[off++] = (uint8_t)lms_dc_cals.tx_lpf_i;
    image->data[off++] = (uint8_t)lms_dc_cals.tx_lpf_q;
    image->data[off++] = (uint8_t)lms_dc_cals.rx_lpf_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rx_lpf_q;
    image->data[off++] = (uint8_t)lms_dc_cals.dc_ref;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2a_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2a_q;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2b_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2b_q;

    putchar('\n');

    for (f = f_low; f <= f_high; f += f_inc) {
        const uint32_t frequency = HOST_TO_LE32((uint32_t)f);
        int16_t dc_i, dc_q;

        printf("  Calibrating @ %u Hz...", f);

        status = bladerf_set_frequency(s->dev, module, f);
        if (status != 0) {
            goto out;
        }

        if (module == BLADERF_MODULE_RX) {
            int16_t error_i, error_q;
            status = calibrate_dc_rx(s, &dc_i, &dc_q, &error_i, &error_q);
            printf("    I=%-4d (avg: %-4d), Q=%-4d (avg: %-4d)\r",
                    dc_i, error_i, dc_q, error_q);
        } else {
            float error_i, error_q;
            status = calibrate_dc_tx(s, &dc_i, &dc_q, &error_i, &error_q);
            printf("    I=%-4d (avg: %3.3f), Q=%-4d (avg: %3.3f)\r",
                    dc_i, error_i, dc_q, error_q);
        }

        if (status != 0) {
            goto out;
        }

        fflush(stdout);

        dc_i = HOST_TO_LE16(dc_i);
        dc_q = HOST_TO_LE16(dc_q);

        memcpy(&image->data[off], &frequency, sizeof(frequency));
        off += sizeof(frequency);

        memcpy(&image->data[off], &dc_i, sizeof(dc_i));
        off += sizeof(dc_i);

        memcpy(&image->data[off], &dc_q, sizeof(dc_q));
        off += sizeof(dc_q);
    }

    status = bladerf_image_write(image, filename);

    printf("\n  Done.\n\n");

out:
    retval = status;

    if (module == BLADERF_MODULE_RX) {
        status = bladerf_set_loopback(s->dev, loopback_backup);
        retval = first_error(retval, status);
    }

    status = bladerf_enable_module(s->dev, BLADERF_MODULE_RX, false);
    retval = first_error(retval, status);

    status = restore_settings(s->dev, module, &settings);
    retval = first_error(retval, status);

    bladerf_free_image(image);
    return retval;
}
static pwr_tStatus IoAgentRead(io_tCtx ctx, io_sAgent* ap)
{
  io_sLocalHilscher_cifX_PnController* local
      = (io_sLocalHilscher_cifX_PnController*)ap->Local;
  pwr_sClass_Hilscher_cifX_PnController* op
      = (pwr_sClass_Hilscher_cifX_PnController*)ap->op;
  int32_t sts;

  if (local->diag_cnt == 0)
    get_diag(&op->Diag, local->chan);
  if (local->diag_cnt > local->diag_interval)
    local->diag_cnt = 0;
  else
    local->diag_cnt++;

  // Read input area
  if (local->input_area_size) {
    sts = xChannelIORead(
        local->chan, 0, 0, local->input_area_size, local->input_area, 10);
    op->Status = sts;
    if (sts == CIFX_NO_ERROR) {
      if (local->dev_init)
        local->dev_init = 0;
    } else {
      if (sts == CIFX_DEV_NO_COM_FLAG && local->dev_init
          && local->dev_init_cnt < local->dev_init_limit)
        local->dev_init_cnt++;
      else {
        xDriverGetErrorDescription(sts, op->ErrorStr, sizeof(op->ErrorStr));
        op->ErrorCount++;
      }
    }

    if (op->ErrorCount == op->ErrorSoftLimit && !local->softlimit_logged) {
      errh_Error("IO Error soft limit reached on agent '%s'", ap->Name);
      local->softlimit_logged = 1;
    }
    if (op->ErrorCount >= op->ErrorHardLimit) {
      ctx->Node->EmergBreakTrue = 1;
      return IO__ERRDEVICE;
    }
  }

  // Get Alarm or Diag

  CIFX_PACKET* msg = (CIFX_PACKET*)calloc(1, sizeof(CIFX_PACKET));

  sts = xChannelGetPacket(local->chan, sizeof(*msg), msg, 0);
  if (sts != CIFX_NO_ERROR) {
    if (!(sts == CIFX_DEV_GET_TIMEOUT || sts == CIFX_DEV_GET_NO_PACKET))
      printf("Diag msg status 0x%08x\n", sts);
  } else {
    printf("Diag message ?\n");

    switch (((TLR_PACKET_HEADER_T*)msg)->ulCmd) {
    case PNIO_APCTL_CMD_APPL_ALARM_IND: {
      // Response, return the package
      APIOC_ALARM_RSP_T alarm_rsp = { { 0 } };

      alarm_rsp.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
      alarm_rsp.tHead.ulLen = HOST_TO_LE32(sizeof(alarm_rsp.tData));
      alarm_rsp.tHead.ulCmd = HOST_TO_LE32(PNIO_APCTL_CMD_APPL_ALARM_RSP);
      alarm_rsp.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
      alarm_rsp.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
      alarm_rsp.tData.ulHandle = ((APIOC_ALARM_IND_T*)msg)->tData.ulHandle;
      alarm_rsp.tData.usAlarmSpecifier
          = ((APIOC_ALARM_IND_T*)msg)->tData.usAlarmSpecifier;

      sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&alarm_rsp, 10);
      printf("Alarm ind\n");

      // Ack the alarm
      APIOC_ALARM_ACK_REQ_T alarm_ack = { { 0 } };
      APIOC_ALARM_ACK_CNF_T alarm_ack_cnf = { { 0 } };

      alarm_ack.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
      alarm_ack.tHead.ulLen = HOST_TO_LE32(sizeof(alarm_ack.tData));
      alarm_ack.tHead.ulCmd = HOST_TO_LE32(PNIO_APCTL_CMD_APPL_ALARM_ACK_CNF);
      alarm_ack.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
      alarm_ack.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
      alarm_ack.tData.ulHandle = ((APIOC_ALARM_IND_T*)msg)->tData.ulHandle;
      alarm_ack.tData.usAlarmSpecifier
          = ((APIOC_ALARM_IND_T*)msg)->tData.usAlarmSpecifier;
      alarm_ack.tData.usReserved = 0;

      sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&alarm_ack, 10);
      if (sts == CIFX_NO_ERROR) {
        sts = xChannelGetPacket(local->chan, sizeof(alarm_ack_cnf),
            (CIFX_PACKET*)&alarm_ack_cnf, 20);
        if (sts == CIFX_NO_ERROR) {
          printf("ALARM_ACK\n");
          printf("Status 0x%08x\n", alarm_ack_cnf.tHead.ulSta);
        }
      }
      break;
    }
    case PNIO_APCTL_CMD_APPL_DIAG_DATA_IND: {
      // Response, return the package
      APIOC_DIAG_DATA_RSP_T diag_data_rsp = { { 0 } };

      diag_data_rsp.tHead.ulDest = HOST_TO_LE32(PNM_APPLICATION);
      diag_data_rsp.tHead.ulLen = HOST_TO_LE32(sizeof(diag_data_rsp.tData));
      diag_data_rsp.tHead.ulCmd
          = HOST_TO_LE32(PNIO_APCTL_CMD_APPL_DIAG_DATA_RSP);
      diag_data_rsp.tHead.ulSrc = HOST_TO_LE32(PN_SRC);
      diag_data_rsp.tHead.ulSrcId = HOST_TO_LE32(PN_SRCID);
      diag_data_rsp.tData.ulHandle
          = ((APIOC_DIAG_DATA_IND_T*)msg)->tData.ulHandle;

      sts = xChannelPutPacket(local->chan, (CIFX_PACKET*)&diag_data_rsp, 10);
      printf("Diag data\n");

      break;
    }
    default:
      printf(
          "Unexpected cmd received: %u\n", ((TLR_PACKET_HEADER_T*)msg)->ulCmd);
    }
  }

  free(msg);

  return IO__SUCCESS;
}
Exemplo n.º 4
0
/* See libbladeRF's dc_cal_table.c for the packed table data format */
int calibrate_dc_gen_tbl(struct cli_state *s, bladerf_module module,
                         const char *filename, unsigned int f_low,
                         unsigned f_inc, unsigned int f_high)
{
    int retval, status;
    size_t off;
    struct bladerf_lms_dc_cals lms_dc_cals;
    unsigned int f;
    struct settings settings;
    bladerf_loopback loopback_backup;
    struct bladerf_image *image = NULL;
    FILE *write_check;

    const uint16_t magic = HOST_TO_LE16(0x1ab1);
    const uint32_t reserved = HOST_TO_LE32(0x00000000);
    const uint32_t tbl_version = HOST_TO_LE32(0x00000001);

    const size_t lms_data_size = 10; /* 10 uint8_t register values */

    const uint32_t n_frequencies = (f_high - f_low) / f_inc + 1;
    const uint32_t n_frequencies_le = HOST_TO_LE32(n_frequencies);

    const size_t entry_size = sizeof(uint32_t) +   /* Frequency */
                              2 * sizeof(int16_t); /* DC I and Q valus */

    const size_t table_size = n_frequencies * entry_size;

    const size_t data_size = sizeof(magic) + sizeof(reserved) +
                             sizeof(tbl_version) + sizeof(n_frequencies_le) +
                             lms_data_size + table_size;

    assert(data_size <= UINT_MAX);

    /* This operation may take a bit of time, so let's make sure we
     * actually have write access before kicking things off.  Note that
     * access is checked later when the file is actually written.
     */
    write_check = fopen(filename, "wb");
    if (write_check == NULL) {
        if (errno == EACCES) {
            return BLADERF_ERR_PERMISSION;
        } else {
            return BLADERF_ERR_IO;
        }
    } else {
        fclose(write_check);

        /* Not much we care to do if this fails. Throw away the return value
         * to make this explicit to our static analysis tools */
        (void) remove(filename);
    }

    status = backup_and_update_settings(s->dev, module, &settings);
    if (status != 0) {
        return status;
    }

    status = bladerf_get_loopback(s->dev, &loopback_backup);
    if (status != 0) {
        return status;
    }

    status = bladerf_lms_get_dc_cals(s->dev, &lms_dc_cals);
    if (status != 0) {
        goto out;
    }

    if (module == BLADERF_MODULE_RX) {
        image = bladerf_alloc_image(BLADERF_IMAGE_TYPE_RX_DC_CAL,
                                    0xffffffff, (unsigned int) data_size);
    } else {
        image = bladerf_alloc_image(BLADERF_IMAGE_TYPE_TX_DC_CAL,
                                    0xffffffff, (unsigned int) data_size);
    }

    if (image == NULL) {
        status = BLADERF_ERR_MEM;
        goto out;
    }

    status = bladerf_get_serial(s->dev, image->serial);
    if (status != 0) {
        goto out;
    }

    if (module == BLADERF_MODULE_RX) {
        status = bladerf_set_loopback(s->dev, BLADERF_LB_NONE);
        if (status != 0) {
            goto out;
        }
    }

    off = 0;

    memcpy(&image->data[off], &magic, sizeof(magic));
    off += sizeof(magic);

    memcpy(&image->data[off], &reserved, sizeof(reserved));
    off += sizeof(reserved);

    memcpy(&image->data[off], &tbl_version, sizeof(tbl_version));
    off += sizeof(tbl_version);

    memcpy(&image->data[off], &n_frequencies_le, sizeof(n_frequencies_le));
    off += sizeof(n_frequencies_le);

    image->data[off++] = (uint8_t)lms_dc_cals.lpf_tuning;
    image->data[off++] = (uint8_t)lms_dc_cals.tx_lpf_i;
    image->data[off++] = (uint8_t)lms_dc_cals.tx_lpf_q;
    image->data[off++] = (uint8_t)lms_dc_cals.rx_lpf_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rx_lpf_q;
    image->data[off++] = (uint8_t)lms_dc_cals.dc_ref;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2a_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2a_q;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2b_i;
    image->data[off++] = (uint8_t)lms_dc_cals.rxvga2b_q;

    putchar('\n');

    for (f = f_low; f <= f_high; f += f_inc) {
        const uint32_t frequency = HOST_TO_LE32((uint32_t)f);
        int16_t dc_i, dc_q;

        printf("  Calibrating @ %u Hz...", f);

        status = bladerf_set_frequency(s->dev, module, f);
        if (status != 0) {
            goto out;
        }

        if (module == BLADERF_MODULE_RX) {
            int16_t error_i, error_q;
            status = calibrate_dc_rx(s, &dc_i, &dc_q, &error_i, &error_q);
            printf("    I=%-4d (avg: %-4d), Q=%-4d (avg: %-4d)\r",
                    dc_i, error_i, dc_q, error_q);
        } else {
            float error_i, error_q;
            status = calibrate_dc_tx(s, &dc_i, &dc_q, &error_i, &error_q);
            printf("    I=%-4d (avg: %3.3f), Q=%-4d (avg: %3.3f)\r",
                    dc_i, error_i, dc_q, error_q);
        }

        if (status != 0) {
            goto out;
        }

        fflush(stdout);

        dc_i = HOST_TO_LE16(dc_i);
        dc_q = HOST_TO_LE16(dc_q);

        memcpy(&image->data[off], &frequency, sizeof(frequency));
        off += sizeof(frequency);

        memcpy(&image->data[off], &dc_i, sizeof(dc_i));
        off += sizeof(dc_i);

        memcpy(&image->data[off], &dc_q, sizeof(dc_q));
        off += sizeof(dc_q);
    }

    status = bladerf_image_write(image, filename);

    printf("\n  Done.\n\n");

out:
    retval = status;

    if (module == BLADERF_MODULE_RX) {
        status = bladerf_set_loopback(s->dev, loopback_backup);
        retval = first_error(retval, status);
    }

    status = bladerf_enable_module(s->dev, BLADERF_MODULE_RX, false);
    retval = first_error(retval, status);

    status = restore_settings(s->dev, module, &settings);
    retval = first_error(retval, status);

    bladerf_free_image(image);
    return retval;
}