Exemple #1
0
/*----------------------------------------------------------------------------*\
   Init method for the Pb module Ao
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardInit (
  io_tCtx	ctx,
  io_sAgent	*ap,
  io_sRack	*rp,
  io_sCard	*cp
) 
{
  io_sCardLocal *local;
  pwr_sClass_Pb_Ao *op;
  io_sChannel *chanp;
  int i;

  op = (pwr_sClass_Pb_Ao *) cp->op;
  local = (io_sCardLocal *) cp->Local;

  if (rp->Class != pwr_cClass_Pb_DP_Slave) {
    errh_Info( "Illegal object type %s", cp->Name );
    return IO__SUCCESS;
  }

  if (op->Status >= PB_MODULE_STATE_OPERATE) {

    // Calculate polycoeff
    for (i=0; i<cp->ChanListSize; i++) {
      chanp = &cp->chanlist[i];
      if (!chanp->cop) continue;
      io_AoRangeToCoef(chanp);
    }
  }
  else
    errh_Info( "Error initializing Pb module Ao %s", cp->Name );

  return IO__SUCCESS;
}
static pwr_tStatus IoCardInit( io_tCtx ctx,
			       io_sAgent *ap,
			       io_sRack *rp,
			       io_sCard *cp)
{
  pwr_sClass_OneWire_AoDevice *op = (pwr_sClass_OneWire_AoDevice *)cp->op;
  io_sLocalAoDevice *local;
  pwr_tStatus sts;
  char name[40];
  pwr_tFileName fname, tmp;
  int name_len;
  char *s;

  if ( cp->chanlist[0].cop) {
    local = (io_sLocalAoDevice *) calloc( 1, sizeof(io_sLocalAoDevice));
    cp->Local = local;

    sprintf( name, "%d-%012x", op->Family, op->Super.Address);
    name_len = strlen(name);
    strncpy( fname, op->DataFile, sizeof(fname));
    
    // Replace all '%s' with 'family-serialnumber'
    s = fname;
    while ( (s = strstr( s, "%s"))) {
      strncpy( tmp, s+2, sizeof(tmp));
      strcpy( s, name);
      strncat( fname, tmp, sizeof(fname));
    }
    local->value_fp = fopen( fname, "w");
    if (!local->value_fp) {
      errh_Error( "OneWire_AoDevice Unable op open %s, '%ux'", cp->Name, 
		  op->Super.Address);
      sts = IO__INITFAIL;
      op->Status = sts;
      return sts;
    }

    io_AoRangeToCoef( &cp->chanlist[0]);

    errh_Info( "Init of OneWire_AoDevice '%s'", cp->Name);
  }
  return IO__SUCCESS;
}
Exemple #3
0
/*----------------------------------------------------------------------------*\
   Write method for the Pb module Ao
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardWrite (
  io_tCtx	ctx,
  io_sAgent	*ap,
  io_sRack	*rp,
  io_sCard	*cp
) 
{
  io_sCardLocal *local;
  pwr_sClass_Pb_Ao *op;
  pwr_sClass_Pb_DP_Slave *slave;
  int i;
  pwr_tInt8 data8 = 0;
  pwr_tInt16 data16 = 0;
  pwr_tInt32 data32 = 0;
  pwr_tUInt8 udata8 = 0;
  pwr_tUInt16 udata16 = 0;
  pwr_tUInt32 udata32 = 0;
  pwr_sClass_ChanAo *cop;
  pwr_sClass_Ao *sop;
  io_sChannel *chanp;
  int fixout;
  pwr_tFloat32 value;
  pwr_tFloat32 rawvalue;

  local = (io_sCardLocal *) cp->Local;
  op = (pwr_sClass_Pb_Ao *) cp->op;
  slave = (pwr_sClass_Pb_DP_Slave *) rp->op;
  
  if (op->Status >= PB_MODULE_STATE_OPERATE && slave->DisableSlave != 1) {

    fixout = ctx->Node->EmergBreakTrue && ctx->Node->EmergBreakSelect == FIXOUT;

    for (i=0; i<cp->ChanListSize; i++) {

      chanp = &cp->chanlist[i];
      if (!chanp->cop || !chanp->sop) continue;

      cop = (pwr_sClass_ChanAo *) chanp->cop;
      sop = (pwr_sClass_Ao *) chanp->sop;

      // Determine what actual value we actually want!
      if (fixout)
        value = cop->FixedOutValue;
      else if (cop->TestOn)
        value = cop->TestValue;
      else {
	value = *(pwr_tFloat32 *) chanp->vbp;
      }

      // Make new coeff.. if necessary
      if (cop->CalculateNewCoef)
        io_AoRangeToCoef(chanp);

      // Convert to rawvalue
      if (value > cop->ActValRangeHigh)
        value = cop->ActValRangeHigh;
      else if ( value < cop->ActValRangeLow)
        value = cop->ActValRangeLow;

      rawvalue = cop->OutPolyCoef1 * value + cop->OutPolyCoef0;

      if ( rawvalue > 0)
        rawvalue = rawvalue + 0.5;
      else
        rawvalue = rawvalue - 0.5;

      // We don´t use RawValue in Profibus I/O
      sop->RawValue = 0;

      // Calculate signal value
      sop->SigValue = cop->SigValPolyCoef1 * value + cop->SigValPolyCoef0;

      if (op->BytesPerChannel == 4) {

	if (op->NumberRepresentation == PB_NUMREP_UNSIGNEDINT) {
          udata32 = (pwr_tUInt32) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) udata32 = swap32(udata32);
          memcpy(local->output_area + op->OffsetOutputs + 4*i, &udata32, 4);
	}
	else if (op->NumberRepresentation == PB_NUMREP_SIGNEDINT) {
          data32 = (pwr_tInt32) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) data32 = swap32(data32);
          memcpy(local->output_area + op->OffsetOutputs + 4*i, &data32, 4);
	}

      }
      else if (op->BytesPerChannel == 3) {

	if (op->NumberRepresentation == PB_NUMREP_UNSIGNEDINT) {
          udata32 = (pwr_tUInt32) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) udata32 = swap32(udata32);
          memcpy(local->output_area + op->OffsetOutputs + 3*i, &udata32, 3);
	}
	else if (op->NumberRepresentation == PB_NUMREP_SIGNEDINT) {
          data32 = (pwr_tInt32) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) data32 = swap32(data32);
          memcpy(local->output_area + op->OffsetOutputs + 3*i, &data32, 3);
	}

      }
      else if (op->BytesPerChannel == 2) {

	if (op->NumberRepresentation == PB_NUMREP_UNSIGNEDINT) {
          udata16 = (pwr_tUInt16) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) udata16 = swap16(udata16);
          memcpy(local->output_area + op->OffsetOutputs + 2*i, &udata16, 2);
        }
	else if (op->NumberRepresentation == PB_NUMREP_SIGNEDINT) {
          data16 = (pwr_tInt16) rawvalue;
          if (slave->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) data16 = swap16(data16);
          memcpy(local->output_area + op->OffsetOutputs + 2*i, &data16, 2);
        }
	
      }
      else if (op->BytesPerChannel == 1) {

	if (op->NumberRepresentation == PB_NUMREP_UNSIGNEDINT) {
          udata8 = (pwr_tUInt8) rawvalue;
          memcpy(local->output_area + op->OffsetOutputs + i, &udata8, 1);
        }	
	else if (op->NumberRepresentation == PB_NUMREP_SIGNEDINT) {
          data8 = (pwr_tInt8) rawvalue;
          memcpy(local->output_area + op->OffsetOutputs + i, &data8, 1);
        }
      }
    }
  }

  return IO__SUCCESS;
}
static pwr_tStatus IoCardInit( io_tCtx ctx,
			       io_sAgent *ap,
			       io_sRack *rp,
			       io_sCard *cp)
{
  int found = 0;
  int i;
  unsigned char port_mask[3] = {255,255,63};
  unsigned char port[3] = {0,0,0};
  int active;
  int timeout;
  io_sLocal *local;
  io_sLocalUSB *localUSB = (io_sLocalUSB *)rp->Local;
  pwr_sClass_MotionControl_USBIO *op = (pwr_sClass_MotionControl_USBIO *)cp->op;

  local = (io_sLocal *) calloc( 1, sizeof(io_sLocal));
  cp->Local = local;

  /* Find the handle in rack local data */
  for ( i = 0; i < (int)sizeof(localUSB->USB_Handle); i++) {
    if ( localUSB->snum[i] == op->Super.Address) {
      found = 1;
      local->USB_Handle = localUSB->USB_Handle[i];
      break;
    }
  }

  if ( !found) {
    errh_Error( "Io init error, USBIO card not found '%s'", cp->Name);
    op->Status = pwr_eMotionControl_StatusEnum_FindDevice;
    return 0;
  }

  op->Status = USBIO_SoftReset( &local->USB_Handle);
  if ( op->Status)
    errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);

  /* Configure port A */
  local->portA_hasDi = 0;
  local->portA_hasDo = 0;
  local->portA_diMask = 0;
  local->portA_doMask = 0;
  for ( i = 0; i < 8; i++) {
    if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanDi) {
      local->portA_hasDi = 1;
      local->portA_diMask |= (1 << i);
    }
    else if ( cp->chanlist[i].cop && 
	      cp->chanlist[i].sop && 
	      cp->chanlist[i].ChanClass == pwr_cClass_ChanDo) {
      local->portA_hasDo = 1;
      local->portA_doMask |= (1 << i);
    }
  }
  if ( local->portA_hasDi || local->portA_hasDo) {
    op->Status = USBIO_ConfigDIO( &local->USB_Handle, 1, local->portA_diMask);
    if ( op->Status)
      errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);
  }

  /* Configure port B */
  local->portB_hasDi = 0;
  local->portB_hasDo = 0;
  local->portB_hasAi = 0;
  for ( i = 8; i < 16; i++) {
    if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanDi) {
      local->portB_hasDi = 1;
      local->portB_diMask |= (1 << (i - 8));
    }
    else if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanDo) {
      local->portB_hasDo = 1;
      local->portB_doMask |= (1 << (i - 8));
    }
    if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 (cp->chanlist[i].ChanClass == pwr_cClass_ChanAi ||
	  cp->chanlist[i].ChanClass == pwr_cClass_ChanAit)) {
      local->portB_hasAi = 1;
      local->portB_aiMask |= (1 << (i - 8));

      // Calculate conversion coefficients
      io_AiRangeToCoef( &cp->chanlist[i]);
    }
  }

  if ( local->portB_hasDi || local->portB_hasDo) {
    op->Status = USBIO_ConfigDIO( &local->USB_Handle, 2, local->portB_diMask);
    if ( op->Status)
      errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);
  }

  if ( local->portB_hasAi) {
    int num_ai;
    for ( i = 0; i < 8; i++) {
      if ( local->portB_aiMask & (1 << i))
	num_ai = i + 1;
    }
    op->Status = USBIO_ConfigAI( &local->USB_Handle, num_ai);
    if ( op->Status)
      errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);
  }
  else
    op->Status = USBIO_ConfigAI( &local->USB_Handle, 0);

  /* Configure port C */
  local->portC_hasDi = 0;
  local->portC_hasDo = 0;
  local->portC_hasAo = 0;
  for ( i = 16; i < 21; i++) {
    if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanDi) {
      local->portC_hasDi = 1;
      local->portC_diMask |= (1 << (i - 16));
    }
    else if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanDo) {
      local->portC_hasDo = 1;
      local->portC_doMask |= (1 << (i - 16));
    }
    if ( cp->chanlist[i].cop && 
	 cp->chanlist[i].sop && 
	 cp->chanlist[i].ChanClass == pwr_cClass_ChanAo) {
      local->portC_hasAo = 1;
      local->portC_aoMask |= (1 << (i - 16));

      // Calculate conversion coefficients
      io_AoRangeToCoef( &cp->chanlist[i]);
    }
  }


  if ( cp->chanlist[18].cop && 
       cp->chanlist[18].sop && 
       cp->chanlist[18].ChanClass == pwr_cClass_ChanIi)
      local->portC_hasIi = 1;

  if ( local->portC_hasDi || local->portC_hasDo) {
    op->Status = USBIO_ConfigDIO( &local->USB_Handle, 3, local->portC_diMask);
    if ( op->Status)
      errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);
  }

  if ( local->portC_hasAo) {
    op->Status = USBIO_ConfigAO( &local->USB_Handle, local->portC_aoMask >> 3);
    if ( op->Status)
      errh_Error( "IO Init Card '%s', Status %d", cp->Name, op->Status);
  }
static pwr_tStatus IoCardWrite( io_tCtx ctx,
				io_sAgent *ap,
				io_sRack	*rp,
				io_sCard	*cp)
{
  io_sLocalAoDevice *local = (io_sLocalAoDevice *)cp->Local;
  pwr_sClass_OneWire_AoDevice *op = (pwr_sClass_OneWire_AoDevice *)cp->op;
  char str[80];
  pwr_tUInt32 error_count = op->Super.ErrorCount;
  int num;

  if ( op->ScanInterval > 1) {
    if ( local->interval_cnt != 0) {
      local->interval_cnt++;
      if ( local->interval_cnt >= op->ScanInterval)
        local->interval_cnt = 0;
      return IO__SUCCESS;
    }
    local->interval_cnt++;
  }

  if ( cp->chanlist[0].cop && cp->chanlist[0].sop) {
    io_sChannel *chanp = &cp->chanlist[0];
    pwr_sClass_ChanAo *cop = (pwr_sClass_ChanAo *)chanp->cop;
    pwr_sClass_Ao *sop = (pwr_sClass_Ao *)chanp->sop;

    if ( cop->CalculateNewCoef)
      // Request to calculate new coefficients
      io_AoRangeToCoef( chanp);

    switch ( op->ChAo.Representation) {

    case pwr_eDataRepEnum_Float32:
    case pwr_eDataRepEnum_Float64: {
      pwr_tFloat32 fvalue;

      fvalue = *(pwr_tFloat32 *)cp->chanlist[0].vbp * cop->OutPolyCoef1 + cop->OutPolyCoef0;
      if ( fvalue > cop->ActValRangeHigh)
        fvalue = cop->ActValRangeHigh;
      else if ( fvalue < cop->ActValRangeLow)
        fvalue = cop->ActValRangeLow;

      if ( fvalue > 0)
        sop->RawValue = fvalue + 0.5;
      else
        sop->RawValue = fvalue - 0.5;

      if ( strcmp( op->Format, "") == 0 )
	num = snprintf( str, sizeof(str), "%f", fvalue);
      else
	num = snprintf( str, sizeof(str), op->Format, fvalue);

      if ( num == 0)
	op->Super.ErrorCount++;
      
      break;
    }
    default: {
      pwr_tInt32 ivalue;
      pwr_tFloat32 fvalue;

      fvalue = *(pwr_tFloat32 *)cp->chanlist[0].vbp * cop->OutPolyCoef1 + cop->OutPolyCoef0;
      if ( fvalue > cop->ActValRangeHigh)
        fvalue = cop->ActValRangeHigh;
      else if ( fvalue < cop->ActValRangeLow)
        fvalue = cop->ActValRangeLow;

      if ( fvalue > 0)
        ivalue = sop->RawValue = fvalue + 0.5;
      else
        ivalue = sop->RawValue = fvalue - 0.5;

      if ( strcmp( op->Format, "") == 0 )
	num = snprintf( str, sizeof(str), "%d", ivalue);
      else
	num = snprintf( str, sizeof(str), op->Format, ivalue);

      if ( num == 0)
	op->Super.ErrorCount++;
    }
    }

    if ( num) {
      fprintf( local->value_fp, "%s", str);
      fflush( local->value_fp);
      rewind( local->value_fp);
    }
  }
  if ( op->Super.ErrorCount >= op->Super.ErrorSoftLimit && 
       error_count < op->Super.ErrorSoftLimit) {
    errh_Warning( "IO Card ErrorSoftLimit reached, '%s'", cp->Name);
  }
  if ( op->Super.ErrorCount >= op->Super.ErrorHardLimit) {
    errh_Error( "IO Card ErrorHardLimit reached '%s', IO stopped", cp->Name);
    ctx->Node->EmergBreakTrue = 1;
    return IO__ERRDEVICE;
  }    

  return IO__SUCCESS;
}
static pwr_tStatus IoRackInit (
  io_tCtx	ctx,
  io_sAgent	*ap,
  io_sRack	*rp
) 
{
  io_sCardLocal *local_card;
  io_sCard *cardp;
  short input_counter;
  short output_counter;
  pwr_sClass_Pb_DP_Slave *op;
  pwr_sClass_Pb_Di *dip;
  pwr_sClass_Pb_Do *dop;
  pwr_sClass_Pb_Ai *aip;
  pwr_sClass_Pb_Ao *aop;
  pwr_sClass_Pb_Ii *iip;
  pwr_sClass_Pb_Io *iop;
  pwr_sClass_Pb_Module *mp;
  char name[196];
  pwr_tStatus sts;
  pwr_tCid cid;
  
  io_sChannel *chanp;
  int i, latent_input_count, latent_output_count;
  pwr_tInt32 chan_size;
  pwr_sClass_ChanDi *chan_di;
  pwr_sClass_ChanDo *chan_do;
  pwr_sClass_ChanAi *chan_ai;
  pwr_sClass_ChanAit *chan_ait;
  pwr_sClass_ChanIi *chan_ii;
  pwr_sClass_ChanAo *chan_ao;
  pwr_sClass_ChanIo *chan_io;

  sts = gdh_ObjidToName(rp->Objid, (char *) &name, sizeof(name), cdh_mNName);
  errh_Info( "Init of Profibus DP Slave and Modules %s", name);

  op = (pwr_sClass_Pb_DP_Slave *) rp->op;
  
  // Do configuration check and initialize modules.

  cardp = rp->cardlist;
  input_counter = 0;
  output_counter = 0;
  op->NumberModules = 0;

  latent_input_count = 0;
  latent_output_count = 0;

  while(cardp) {
    local_card = calloc(1, sizeof(*local_card));
    cardp->Local = local_card;
    local_card->input_area = (void *) &(op->Inputs);
    local_card->output_area = (void *) &(op->Outputs);

    /* From v4.1.3 we can have subclasses, find the super class */
    
    cid = cardp->Class;
    while ( ODD( gdh_GetSuperClass( cid, &cid, cardp->Objid))) ;

    switch (cid) {

      /* Old style configuring with Pb_xx objects. Still here for combatibility reasons. 
         New systems (from v4.1.3) should be build with Pb_Module objects or subclasses */
	 
      case pwr_cClass_Pb_Di:
        dip = (pwr_sClass_Pb_Di *) cardp->op;
        dip->OffsetInputs = input_counter;
        dip->BytesOfInput = dip->NumberOfChannels / 8;
        input_counter += dip->BytesOfInput;
        dip->Status = PB_MODULE_STATE_OPERATE;
        break;

      case pwr_cClass_Pb_Do:
        dop = (pwr_sClass_Pb_Do *) cardp->op;
        dop->OffsetOutputs = output_counter;
        dop->BytesOfOutput = dop->NumberOfChannels / 8;
        output_counter += dop->BytesOfOutput;
        dop->Status = PB_MODULE_STATE_OPERATE;
        break;

      case pwr_cClass_Pb_Ai:
        aip = (pwr_sClass_Pb_Ai *) cardp->op;
        aip->OffsetInputs = input_counter;
        aip->BytesOfInput = aip->NumberOfChannels * aip->BytesPerChannel;
        input_counter += aip->BytesOfInput;
        aip->Status = PB_MODULE_STATE_OPERATE;
        break;

      case pwr_cClass_Pb_Ao:
        aop = (pwr_sClass_Pb_Ao *) cardp->op;
        aop->OffsetOutputs = output_counter;
        aop->BytesOfOutput = aop->NumberOfChannels * aop->BytesPerChannel;
        output_counter += aop->BytesOfOutput;
        aop->Status = PB_MODULE_STATE_OPERATE;
        break;

      case pwr_cClass_Pb_Ii:
        iip = (pwr_sClass_Pb_Ii *) cardp->op;
        iip->OffsetInputs = input_counter;
        iip->BytesOfInput = iip->NumberOfChannels * iip->BytesPerChannel;
        input_counter += iip->BytesOfInput;
        iip->Status = PB_MODULE_STATE_OPERATE;
        break;

      case pwr_cClass_Pb_Io:
        iop = (pwr_sClass_Pb_Io *) cardp->op;
        iop->OffsetOutputs = output_counter;
        iop->BytesOfOutput = iop->NumberOfChannels * iop->BytesPerChannel;
        output_counter += iop->BytesOfOutput;
        iop->Status = PB_MODULE_STATE_OPERATE;
        break;

      /* New style configuring (from v4.1.3) with Pb_Module objects or subclass. Loop all channels
        in the module and set channel size and offset. */	 

      case pwr_cClass_Pb_Module:
        mp = (pwr_sClass_Pb_Module *) cardp->op;
        mp->Status = PB__INITFAIL;
	cardp->offset = 0;
        for (i=0; i<cardp->ChanListSize; i++) {
          chanp = &cardp->chanlist[i];

	  if ( is_diag( &chanp->ChanAref)) {
	    chanp->udata |= PB_UDATA_DIAG;
	    switch (chanp->ChanClass) {	    
            case pwr_cClass_ChanIi:
	      chanp->offset = ((pwr_sClass_ChanIi *)chanp->cop)->Number;
	      chanp->size = GetChanSize( ((pwr_sClass_ChanIi *)chanp->cop)->Representation);
	      break;
	    default:
	      errh_Error( "Diagnostic channel class, card %s", cardp->Name);
	    }
	    continue;
	  }

          if (chanp->ChanClass != pwr_cClass_ChanDi) {
            input_counter += latent_input_count;
	    latent_input_count = 0;
          }

          if (chanp->ChanClass != pwr_cClass_ChanDo) {
            output_counter += latent_output_count;
	    latent_output_count = 0;
          }
      
          switch (chanp->ChanClass) {
      
            case pwr_cClass_ChanDi:
	      chan_di = (pwr_sClass_ChanDi *) chanp->cop;
              if (chan_di->Number == 0) {
	        input_counter += latent_input_count;
	        latent_input_count = 0;
	      }
              chanp->offset = input_counter;
	      chanp->mask = 1<<chan_di->Number;
	      if (chan_di->Representation == pwr_eDataRepEnum_Bit16 && op->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) 
	        chanp->mask = swap16(chanp->mask);
	      if (chan_di->Representation == pwr_eDataRepEnum_Bit32 && op->ByteOrdering == pwr_eByteOrderingEnum_BigEndian)
	        chanp->mask = swap32((unsigned short) chanp->mask);
	      if (chan_di->Number == 0) latent_input_count = GetChanSize(chan_di->Representation);
//	      printf("Di channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_di->Number, chanp->offset);
	      break;
	  
            case pwr_cClass_ChanAi:
	      chan_ai = (pwr_sClass_ChanAi *) chanp->cop;
              chanp->offset = input_counter;
	      chan_size = GetChanSize(chan_ai->Representation);
              chanp->size = chan_size;
	      chanp->mask = 0;
	      input_counter += chan_size;
              io_AiRangeToCoef(chanp);
//	      printf("Ai channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ai->Number, chanp->offset);
	      break;
	  
            case pwr_cClass_ChanAit:
	      chan_ait = (pwr_sClass_ChanAit *) chanp->cop;
              chanp->offset = input_counter;
	      chan_size = GetChanSize(chan_ait->Representation);
              chanp->size = chan_size;
	      chanp->mask = 0;
	      input_counter += chan_size;
              io_AiRangeToCoef(chanp);
	      break;
	  
            case pwr_cClass_ChanIi:
	      chan_ii = (pwr_sClass_ChanIi *) chanp->cop;
              chanp->offset = input_counter;
	      chan_size = GetChanSize(chan_ii->Representation);
              chanp->size = chan_size;
	      chanp->mask = 0;
	      input_counter += chan_size;
//	      printf("Ii channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ii->Number, chanp->offset);
	      break;
	  
            case pwr_cClass_ChanDo:
	      chan_do = (pwr_sClass_ChanDo *) chanp->cop;
              if (chan_do->Number == 0) {
	        output_counter += latent_output_count;
	        latent_output_count = 0;
	      }
              chanp->offset = output_counter;
	      chan_size = GetChanSize(chan_do->Representation);
	      chanp->mask = 1<<chan_do->Number;
	      if (chan_do->Representation == pwr_eDataRepEnum_Bit16 && op->ByteOrdering == pwr_eByteOrderingEnum_BigEndian) 
	        chanp->mask = swap16(chanp->mask);
	      if (chan_do->Representation == pwr_eDataRepEnum_Bit32 && op->ByteOrdering == pwr_eByteOrderingEnum_BigEndian)
	        chanp->mask = swap32((unsigned short) chanp->mask);
	      if (chan_do->Number == 0) latent_output_count = GetChanSize(chan_do->Representation);
//	      printf("Do channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_do->Number, chanp->offset);
	      break;
	  
	    case pwr_cClass_ChanAo:
	      chan_ao = (pwr_sClass_ChanAo *) chanp->cop;
              chanp->offset = output_counter;
	      chan_size = GetChanSize(chan_ao->Representation);
              chanp->size = chan_size;
	      chanp->mask = 0;
	      output_counter += chan_size;
              io_AoRangeToCoef(chanp);
//	      printf("Ao channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ao->Number, chanp->offset);
	      break;
	  
            case pwr_cClass_ChanIo:
	      chan_io = (pwr_sClass_ChanIo *) chanp->cop;
              chanp->offset = output_counter;
	      chan_size = GetChanSize(chan_io->Representation);
              chanp->size = chan_size;
	      chanp->mask = 0;
	      output_counter += chan_size;
//	      printf("Io channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_io->Number, chanp->offset);
	      break;
          }
        }

        mp->Status = PB__NOCONN;
        break;
    }

    op->NumberModules++;
    cardp = cardp->next;
  }

  return IO__SUCCESS;
}
static pwr_tStatus IoCardInit( io_tCtx ctx,
			       io_sAgent *ap,
			       io_sRack *rp,
			       io_sCard *cp)
{
  ssize_t devnum;
  libusb_device **list;
  libusb_device *device = 0;
  int found = 0;
  int i;
  io_sLocalUSB_Agent *local_agent = (io_sLocalUSB_Agent *)ap->Local;
  io_sLocal_K8055 *local;
  pwr_sClass_Velleman_K8055_Board *op = (pwr_sClass_Velleman_K8055_Board *)cp->op;
  int sts;

  if ( !local_agent->libusb_ctx)
    return IO__INITFAIL;

  devnum = libusb_get_device_list( local_agent->libusb_ctx, &list);
  if ( devnum > 0) {

    for ( i = 0; i < devnum; i++) {
      struct libusb_device_descriptor desc;

      if ( libusb_get_device_descriptor( list[i], &desc) != 0)
	continue;

      if ( desc.idVendor == 0x10cf &&
	   desc.idProduct == 0x5500 + op->Super.Address) {
	device = list[i];
	found = 1;
	break;
      }
    }
  }

  if ( !found) {
    errh_Error( "Init Velleman K8055, device not found '%s'", cp->Name);
    op->Status = IO__NODEVICE;
    ((pwr_sClass_Velleman_K8055 *)rp->op)->Status = op->Status;
    return IO__INITFAIL;
  }
  
  local = (io_sLocal_K8055 *) calloc( 1, sizeof(io_sLocal_K8055));
  cp->Local = local;

  sts = libusb_open( device, &local->libusb_device);
  if ( sts != 0) {
    if ( sts == io_cLibDummy)
      op->Status = IO__DUMMYBUILD;
    else
      op->Status = IO__INITFAIL;
    ((pwr_sClass_Velleman_K8055 *)rp->op)->Status = op->Status;
    local->libusb_device = 0;
    return op->Status;
  }

  if ( libusb_kernel_driver_active( local->libusb_device, 0) != 0)
    libusb_detach_kernel_driver( local->libusb_device, 0);

  sts = libusb_claim_interface( local->libusb_device, 0);
  if ( sts < 0) {
    errh_Error( "K8055 Claim interface failed, sts %d, '%s'", sts, ap->Name);
    op->Status = IO__INITFAIL;
    ((pwr_sClass_Velleman_K8055 *)rp->op)->Status = op->Status;
    return IO__INITFAIL;
  }


  for ( i = 0; i < 2; i++) {
    if ( cp->chanlist[i].sop)
      io_AiRangeToCoef( &cp->chanlist[i]);
  }
  for ( i = 0; i < 2; i++) {
    if ( cp->chanlist[i+7].sop)
      io_AoRangeToCoef( &cp->chanlist[i+7]);
  }


  errh_Info( "Init of Velleman K8055 '%s'", cp->Name);
  op->Status = IO__SUCCESS;

  // Rack has no methods, set status
  if ( ((pwr_sClass_Velleman_K8055 *)rp->op)->Status == 0)
    ((pwr_sClass_Velleman_K8055 *)rp->op)->Status = op->Status;

  return IO__SUCCESS;
}
static pwr_tStatus IoCardWrite( io_tCtx ctx,
			       io_sAgent *ap,
			       io_sRack	*rp,
			       io_sCard	*cp)
{
  io_sLocal_K8055 *local = (io_sLocal_K8055 *)cp->Local;
  pwr_sClass_Velleman_K8055_Board *op = (pwr_sClass_Velleman_K8055_Board *)cp->op;
  unsigned char data[9];
  char endpoint = 0x1;
  int size = 8;
  int tsize;
  unsigned char m;
  int i;
  int sts;
  pwr_tUInt32 error_count = op->Super.ErrorCount;

  memset( data, 0, sizeof(data));
  data[0] = 0x5;

  // Handle Do
  m = 1;
  unsigned char do_value = 0;
  for ( i = 0; i < 8; i++) {
    if ( cp->chanlist[i+9].sop) {
      if ( *(pwr_tBoolean *)cp->chanlist[i+9].vbp)
	do_value |= m;
    }
    m = m << 1;
  }
  data[1] = do_value;

  // Handle Ao
  for ( i = 0; i < 2; i++) {
    if ( cp->chanlist[i+7].sop) {
      io_sChannel *chanp = &cp->chanlist[i+7];
      pwr_sClass_ChanAo *cop = (pwr_sClass_ChanAo *)chanp->cop;


      if ( cop->CalculateNewCoef)
	// Request to calculate new coefficients
	io_AoRangeToCoef( chanp);

      float fvalue = *(pwr_tFloat32 *)chanp->vbp * cop->OutPolyCoef1 + cop->OutPolyCoef0;
      int ivalue = (int)fvalue;
      if ( ivalue < 0)
	ivalue = 0;
      else if (ivalue > 255)
	ivalue = 255;

      data[i+2] = ivalue;
    }
  }

  sts = libusb_interrupt_transfer( local->libusb_device, endpoint, data, size, &tsize, 100);
  if ( sts != 0 || tsize != size) {
    op->Super.ErrorCount++;
    if ( sts != 0 && sts != last_usblib_sts) {
      errh_Error( "K8055 libusb transfer error %d", sts);
      last_usblib_sts = sts;
    }
    return IO__SUCCESS;
  }

  if ( op->Super.ErrorCount >= op->Super.ErrorSoftLimit && 
       error_count < op->Super.ErrorSoftLimit) {
    errh_Warning( "IO Card ErrorSoftLimit reached, '%s'", cp->Name);
  }
  if ( op->Super.ErrorCount >= op->Super.ErrorHardLimit) {
    errh_Error( "IO Card ErrorHardLimit reached '%s', IO stopped", cp->Name);
    ctx->Node->EmergBreakTrue = 1;
    return IO__ERRDEVICE;
  }    

  return IO__SUCCESS;
}