Example #1
0
// before device is removed in response to IRP_MN_REMOVE_DEVICE
VOID
RoboDeviceEvtDeviceContextCleanup(
    IN WDFOBJECT Device
    )
{
    //PFDO_DATA   fdoData;
    UNREFERENCED_PARAMETER(Device);

    info0( "RoboDeviceEvtDeviceContextCleanup called\n" );

    PAGED_CODE();

    return;
}
Example #2
0
int dorun(ub4 fln,enum Runlvl stage,bool silent)
{
  int run;

  vrb(0,"dorun stage %u stopat %u",stage, globs.stopat);
  if (stage >= globs.stopat) run = 0;
  else if (stage >= Runcnt) run = 1;
  else run = globs.doruns[stage];
  if (silent) return run;

  info0(User,"");
  infofln(fln,0,"--- %s stage %u %s ---",run ? "run" : "skip",stage,runlvlnames(stage));
  return run;
}
Example #3
0
// IRP_MN_STOP_DEVICE, IRP_MN_REMOVE_DEVICE
NTSTATUS
RoboDeviceEvtDeviceReleaseHardware(
    IN  WDFDEVICE    Device,
    IN  WDFCMRESLIST ResourcesTranslated
    )
{
    //PFDO_DATA   fdoData;

    UNREFERENCED_PARAMETER(Device);
    UNREFERENCED_PARAMETER(ResourcesTranslated);

    info0( "RoboDeviceEvtDeviceReleaseHardware called\n" );

    PAGED_CODE();

    // here - cleanup resources. Unmap memory and I/O ports

    return STATUS_SUCCESS;
}
Example #4
0
int prepnet(netbase *basenet)
{
  struct gnetwork *gnet = getgnet();
  struct portbase *bports,*bpp;
  struct subportbase *bsports,*bspp;
  struct hopbase *bhops,*bhp;
  struct sidbase *bsids,*bsp;
  struct chainbase *bchains,*bcp;
  struct routebase *broutes,*brp;

  ub8 *bchip,*bchainidxs;
  struct chainhopbase *bchp,*bchainhops;

  struct port *ports,*pdep,*parr,*pp;
  struct sport *sports,*spp;
  struct hop *hops,*hp;
  struct sidtable *sids,*sp;
  struct chain *chains,*cp;
  struct route *routes,*rp;
  struct timepatbase *btp;
  struct timepat *tp;

  ub4 bportcnt,portcnt;
  ub4 bsportcnt,sportcnt;
  ub4 bhopcnt,hopcnt;
  ub4 dep,arr;
  ub4 bsidcnt,sidcnt,bchaincnt,chaincnt,chainhopcnt;
  ub4 bridcnt,ridcnt;
  ub4 nlen,cnt,acnt,dcnt,sid,rid,rrid;

  enum txkind kind;
  ub4 hop,port,sport,chain;

  ub4 *rrid2rid = basenet->rrid2rid;
  ub4 hirrid = basenet->hirrid;

  bhopcnt = basenet->hopcnt;
  bportcnt = basenet->portcnt;
  bsportcnt = basenet->subportcnt;
  bsidcnt = basenet->sidcnt;
  bridcnt = basenet->ridcnt;
  bchaincnt = basenet->rawchaincnt;
  if (bportcnt == 0 || bhopcnt == 0) return error(0,"prepnet: %u ports, %u hops",bportcnt,bhopcnt);

  // filter but leave placeholder in gnet to make refs match
  ports = alloc(bportcnt,struct port,0,"ports",bportcnt);
  portcnt = 0;
  bports = basenet->ports;
  for (port = 0; port < bportcnt; port++) {
    bpp = bports + port;
    pp = ports + port;
    nlen = bpp->namelen;
    if (bpp->ndep == 0 && bpp->narr == 0) {
      info(0,"skip unconnected port %u %s",port,bpp->name);
      if (nlen) memcpy(pp->name,bpp->name,nlen);
      pp->namelen = nlen;
      continue;
    }

    // new ndep,narr filled lateron
    pp->valid = 1;
    pp->id = pp->allid = pp->gid = portcnt;
    pp->cid = bpp->cid;
    nlen = bpp->namelen;
    if (nlen) {
      memcpy(pp->name,bpp->name,nlen);
      pp->namelen = nlen;
    } else info(0,"port %u has no name", port);
    pp->lat = bpp->lat;
    // error_z(pp->lat,port);
    pp->lon = bpp->lon;
    pp->rlat = bpp->rlat;
    pp->rlon = bpp->rlon;
    pp->utcofs = bpp->utcofs;
    pp->modes = bpp->modes;
    pp->subcnt = bpp->subcnt;
    pp->subofs = bpp->subofs;
    portcnt++;
  }
  info(0,"%u from %u ports",portcnt,bportcnt);
  portcnt = bportcnt;

  sports = alloc(bsportcnt,struct sport,0,"sports",bsportcnt);
  sportcnt = 0;
  bsports = basenet->subports;
  for (sport = 0; sport < bsportcnt; sport++) {
    bspp = bsports + sport;
    spp = sports + sport;
    nlen = bspp->namelen;
    if (nlen) memcpy(spp->name,bspp->name,nlen);
    else info(0,"sport %u has no name", sport);
    spp->namelen = nlen;
    if (bspp->ndep == 0 && bspp->narr == 0) {
      vrb0(Notty,"unconnected subport %u %s",sport,bspp->name);
//      continue;
    }

    spp->valid = 1;
    spp->id = sportcnt;
    spp->cid = bspp->cid;
    spp->parent = bspp->parent;
    spp->lat = bspp->lat;
    error_z(spp->lat,sport);
    spp->lon = bspp->lon;
    spp->rlat = bspp->rlat;
    spp->rlon = bspp->rlon;
    spp->modes = bspp->modes;
    spp->seq = bspp->seq;
    sportcnt++;
  }
  info(0,"%u from %u sports",sportcnt,bsportcnt);
  sportcnt = bsportcnt;

  sidcnt = bsidcnt;
  sids = alloc(sidcnt,struct sidtable,0,"sids",sidcnt);
  bsids = basenet->sids;
  for (sid = 0; sid < bsidcnt; sid++) {
    bsp = bsids + sid;
    sp = sids + sid;
    sp->sid = bsp->sid;
    sp->t0 = bsp->t0;
    sp->t1 = bsp->t1;
    nlen = bsp->namelen;
    if (nlen) {
      memcpy(sp->name,bsp->name,nlen);
      sp->namelen = nlen;
    }
  }
  info(0,"%u sids",sidcnt);

  ub4 cumrhops = 0,cumrhops2 = 0;

  ub4 ofs = 0;

  ridcnt = bridcnt;
  routes = alloc(ridcnt,struct route,0,"routes",ridcnt);
  broutes = basenet->routes;
  for (rid = 0; rid < ridcnt; rid++) {
    brp = broutes + rid;
    rp = routes + rid;
    rp->rrid = brp->rrid;
    rp->kind = brp->kind;
    rp->reserve = brp->reserve;
    rp->chainofs = brp->chainofs;
    rp->chaincnt = brp->chaincnt;
    cnt = rp->hopcnt = brp->hopcnt;
    rp->hichainlen = brp->hichainlen;
    nlen = brp->namelen;
    if (nlen) {
      memcpy(rp->name,brp->name,nlen);
      rp->namelen = nlen;
    }
    rp->hop2pos = ofs;
    ofs += cnt * cnt;
  }
  info(0,"%u routes",ridcnt);
  cumrhops = ofs;

  block *ridhopmem = &gnet->ridhopmem;
  gnet->ridhopbase = mkblock(ridhopmem,cumrhops + cumrhops2,ub4,Init1,"net");

  ub4 *gportsbyhop = alloc(bhopcnt * 2, ub4,0xff,"net portsbyhop",bhopcnt);
  ub4 dist,*hopdist = alloc(bhopcnt,ub4,0,"net hopdist",bhopcnt);
  ub4 midur,*hopdur = alloc(bhopcnt,ub4,0,"net hopdur",bhopcnt);

  ub4 *drids,*arids,*deps,*arrs;
  ub4 t0,t1,tdep,prvtdep,evcnt;

  hops = alloc(bhopcnt,struct hop,0,"hops",bhopcnt);
  hopcnt = 0;
  bhops = basenet->hops;
  for (hop = 0; hop < bhopcnt; hop++) {
    bhp = bhops + hop;
    dep = bhp->dep;
    arr = bhp->arr;
    error_ge(dep,portcnt);
    error_ge(arr,portcnt);
    if (dep == arr) {
      bpp = bports + dep;
      warning(0,"nil hop %u %s at %u",dep,bpp->name,bhp->cid);
      continue;
    } else if (bhp->valid == 0) {
      bpp = bports + dep;
      warning(0,"invalid hop %u %s at %u",dep,bpp->name,bhp->cid);
      continue;
    }

    pdep = ports + dep;
    parr = ports + arr;
    error_z(pdep->valid,hop);
    error_z(parr->valid,hop);

    gportsbyhop[hop * 2] = dep;
    gportsbyhop[hop * 2 + 1] = arr;

    hp = hops + hop;
    hp->gid = hop;
    nlen = bhp->namelen;
    if (nlen) {
      memcpy(hp->name,bhp->name,nlen);
      hp->namelen = nlen;
    }
    rrid = bhp->rrid;
    error_gt(rrid,hirrid,hop);
    hp->rrid = rrid;
    rid = rrid2rid[rrid];
    hp->rid = rid;
    if (rid != hi32) {
      rp = routes + rid;
      hp->reserve = rp->reserve;
    } else {
      rp = NULL;
      hp->reserve = 0;
    }
    hp->rhop = bhp->rhop;

    tp = &hp->tp;
    btp = &bhp->tp;
    t0 = btp->t0;
    t1 = btp->t1;
    evcnt = btp->evcnt;
    tp->utcofs = btp->utcofs;
    tp->tdays = btp->tdays;
    tp->gt0 = btp->gt0;
    tp->t0 = t0;
    tp->t1 = t1;

    tp->evcnt = evcnt;
    tp->genevcnt = btp->genevcnt;
    noexit error_ne(tp->genevcnt,evcnt); // todo
    tp->genevcnt = min(tp->genevcnt,evcnt);
    tp->evofs = btp->evofs;
    tp->dayofs = btp->dayofs;

    tp->lodur = btp->lodur;
    tp->hidur = btp->hidur;
    midur = tp->midur = btp->midur;
    hopdur[hop] = midur;
    tp->avgdur = btp->avgdur;
    tp->duracc = btp->duracc;

    // mark local links
    pdep = ports + dep;
    parr = ports + arr;
    dcnt = pdep->ndep;
    deps = pdep->deps;
    drids = pdep->drids;
    if (dcnt == 0) {
      deps[0] = hop;
      drids[0] = rid;
      pdep->ndep = 1;
    } else if (dcnt == 1) {
      if (deps[0] != hop || drids[0] != rid) {
        deps[1] = hop;
        drids[1] = rid;
        pdep->ndep = 2;
      }
    } else if ( (deps[0] == hop && drids[0] == rid) || (deps[1] == hop && drids[1] == rid) ) ;
    else pdep->ndep = dcnt + 1;

    acnt = parr->narr;
    arrs = parr->arrs;
    arids = parr->arids;
    if (acnt == 0) {
      arrs[0] = hop;
      arids[0] = rid;
      parr->narr = 1;
    } else if (acnt == 1) {
      if (arrs[0] != hop || arids[0] != rid) {
        arrs[1] = hop;
        arids[1] = rid;
        parr->narr = 2;
      }
    } else if ( (arrs[0] == hop && arids[0] == rid) || (arrs[1] == hop && arids[1] == rid) ) ;
    else parr->narr = acnt + 1;

    kind = bhp->kind;
    hp->kind = kind;

    dist = hp->dist = bhp->dist;
    hopdist[hop] = dist;
    error_z(dist,hop);

    hp->dep = dep;
    hp->arr = arr;
    hopcnt++;
  }
  if (hopcnt == 0) return error(0,"nil hops out of %u",bhopcnt);
  info(0,"%u from %u hops",hopcnt,bhopcnt);
  hopcnt = bhopcnt;

  // prepare <rid,dep,arr> to hop lookup
  ub4 rhop,rhopovf = 0;

  for (hop = 0; hop < hopcnt; hop++) {
    hp = hops + hop;
    rid = hp->rid;
    if (rid == hi32) continue;
    error_ge(rid,ridcnt);
    rp = routes + rid;
    rhop = hp->rhop;
    if (rhop < Chainlen) rp->hops[rhop] = hop;
    else rhopovf++;
  }
  warncc(rhopovf,0,"%u of %u hops exceeding %u chain limit",rhopovf,hopcnt,Chainlen);

  ub4 *bbox = gnet->bbox;

  // bbox of connected ports
  for (port = 0; port < portcnt; port++) {
    pp = ports + port;
    if (pp->ndep == 0 && pp->narr == 0) continue;
    updbbox(pp->lat,pp->lon,bbox,Elemcnt(gnet->bbox));
  }
  info(0,"bbox lat %u - %u = %u",bbox[Minlat],bbox[Maxlat],bbox[Latrng]);
  info(0,"bbox lon %u - %u = %u",bbox[Minlon],bbox[Maxlon],bbox[Lonrng]);

  ub4 oneridcnt = 0;
  ub4 onerid;
  bool oneroute;
  ub4 ndep,narr;

  // mark single-route only ports  
  for (port = 0; port < portcnt; port++) {
    pp = ports + port;
    ndep = pp->ndep;
    narr = pp->narr;
    drids = pp->drids;
    arids = pp->arids;
    arrs = pp->arrs;
    deps = pp->deps;

    oneroute = 0; onerid = 0;
    if (ndep == 0 && narr == 0) continue;
    else if (ndep > 2 || narr > 2) continue;
    else if (ndep == 0 && narr == 1 && arids[0] != hi32) {
      oneroute = 1;
      pp->onerid = arids[0];
    } else if (ndep == 1 && narr == 0 && drids[0] != hi32) {
      oneroute = 1;
      pp->onerid = drids[0];
    } else if (ndep == 1 && narr == 1 && drids[0] == arids[0] && drids[0] != hi32) {
      oneroute = 1;
      pp->onerid = arids[0];
    } else if (ndep == 2 && narr == 2 && drids[0] != hi32 && drids[1] != hi32) {
      if (drids[0] == drids[1] && arids[0] == arids[1] && drids[0] == arids[0]) {
        oneroute = 1;
        pp->onerid = arids[0];
      } else if (drids[0] == arids[0] && drids[1] == arids[1]) {
        if (sameroute2a(hops,port,drids,deps,arrs)) {
          oneroute = 1;
          pp->onerid = arids[0];
        }
      } else if (drids[0] == arids[1] && drids[1] == arids[0]) {
        if (sameroute2b(hops,port,drids,deps,arrs)) {
          oneroute = 1;
          pp->onerid = arids[0];
        }
      }
    }
    if (oneroute) {
      pp->oneroute = 1;
      pp->onerid = onerid;
      oneridcnt++;
    }
  }

  info0(0,"global connectivity");
  showconn(ports,portcnt,0);

  ub4 i,idx,bofs,seq,prvseq,rtid;

  chains = alloc(bchaincnt,struct chain,0,"chains",bchaincnt);
  bchains = basenet->chains;
  bchainhops = basenet->chainhops;
  bchainidxs = basenet->chainidxs;
  chaincnt = chainhopcnt = ofs = 0;
  for (chain = 0; chain < bchaincnt; chain++) {
    bcp = bchains + chain;
    cp = chains + chain;
    cp->rid = bcp->rid;
    cp->tripno = bcp->tripno;
    cnt = bcp->hopcnt;
    if (cnt < 3) { vrb(0,"skip dummy chain %u with %u hop\as",chain,cnt); continue; }
    cp->hopcnt = cnt;
    cp->rhopcnt = bcp->rhopcnt;
    cp->rrid = bcp->rrid;
    cp->rid = bcp->rid;
    cp->tid = chain;
    cp->rtid = bcp->rtid;
    cp->hopofs = ofs;
    ofs += cnt;
    chaincnt++;
  }
  chainhopcnt = ofs;
  info(0,"%u from %u chains with %u hops",chaincnt,bchaincnt,chainhopcnt);
  chaincnt = bchaincnt;

  ub4 *tid2rtid = alloc(chaincnt,ub4,0,"chain tid2rtid",chaincnt);
  struct chainhop *chp,*chainhops = alloc(chainhopcnt,struct chainhop,0,"chain hops",chainhopcnt);

  // write in sorted order
  for (chain = 0; chain < chaincnt; chain++) {
    cp = chains + chain;
    bcp = bchains + chain;
    cnt = cp->hopcnt;
    rtid = cp->rtid;
    tid2rtid[chain] = rtid;
    if (cnt < 3) continue;

    ofs = cp->hopofs;
    bofs = bcp->hopofs;
    bchip = bchainidxs + bofs;
    cp->rhopcnt = bcp->rhopcnt;
    cp->rhopofs = bcp->rhopofs;
    seq = prvtdep = 0;
    for (i = 0; i < cnt; i++) {
      chp = chainhops + ofs + i;
      idx = bchip[i] & hi32;
      error_ge(idx,cnt);
      bchp = bchainhops + bofs + idx;
      prvseq = seq;
      seq = (ub4)(bchip[i] >> 32);
      hop = bchp->hop;
      tdep = bchp->tdep;
      error_le(seq,prvseq);
      chp->hop = hop;
      chp->tdep = tdep;
      noexit error_lt(tdep,prvtdep); // todo day wrap ?
      prvtdep = tdep;
      chp->tarr = bchp->tarr;
      error_lt(chp->tarr,chp->tdep);
      chp->midur = bchp->midur;
    }
  }

  gnet->portcnt = portcnt;
  gnet->sportcnt = sportcnt;
  gnet->hopcnt = hopcnt;
  gnet->sidcnt = sidcnt;
  gnet->chaincnt = chaincnt;
  gnet->ridcnt = ridcnt;

  gnet->ports = ports;
  gnet->sports = sports;
  gnet->hops = hops;
  gnet->sids = sids;
  gnet->chains = chains;
  gnet->routes = routes;

  gnet->portsbyhop = gportsbyhop;
  gnet->hopdist = hopdist;
  gnet->hopdur = hopdur;

  gnet->chainhops = chainhops;
  gnet->chainrhops = basenet->chainrhops;
  gnet->chainrphops = basenet->chainrphops;
  gnet->chainhopcnt = chainhopcnt;

  gnet->hirrid = hirrid;
  gnet->rrid2rid = rrid2rid;

  gnet->tid2rtid = tid2rtid;
  gnet->hichainlen = basenet->hichainlen;

  gnet->eventmem = &basenet->eventmem;
  gnet->evmapmem = &basenet->evmapmem;
  gnet->events = basenet->events;
  gnet->evmaps = basenet->evmaps;
  gnet->t0 = basenet->t0;
  gnet->t1 = basenet->t1;

  gnet->walklimit = m2geo(globs.walklimit);
  gnet->sumwalklimit = m2geo(globs.sumwalklimit);
  gnet->walkspeed = m2geo(globs.walkspeed);

  info(0,"precomputed walk limit set to %u m, summed %u",globs.walklimit,globs.sumwalklimit);

  // write reference for name lookup
  if (wrportrefs(basenet)) return 1;

//  if (condense(gnet)) return 1; not (yet?)

  return 0;
}
Example #5
0
// add compound hops
int compound(gnet *net)
{
  ub4 rportcnt,rport2,portcnt = net->portcnt;
  ub4 hopcnt = net->hopcnt;
  ub4 hop,chop,chopcnt,newhopcnt = 0,newcnt;
  ub4 rid,rrid,ridcnt = net->ridcnt;
  ub4 chain,chaincnt = net->chaincnt;

  ub4 hichainlen = net->hichainlen;
  ub4 hiportlen;
  struct hop *hp,*hp1,*hp2,*hops = net->hops;
  struct port *pdep,*parr,*ports = net->ports;
  struct route *rp,*routes = net->routes;
  struct chain *cp,*chains = net->chains;
  struct chainhop *chp,*chainhops = net->chainhops;
  ub8 *crp,*chainrhops = net->chainrhops;
  ub4 maxperm = min(cmp_maxperm,Chainlen);
  ub4 maxperm2 = maxperm * maxperm;

  ub4 dep,arr,deparr,da,prvda,rdep,rarr;
  int docompound;

  net->chopcnt = hopcnt;

  if (hopcnt == 0) return info(0,"skip compound on %u hop\as",hopcnt);

  net->hopcdur = alloc(hopcnt,ub4,0xff,"net hopcdur",hopcnt); // fallback

  if (portcnt < 3) return info(0,"skip compound on %u port\as",portcnt);
  if (hopcnt < 2) return info(0,"skip compound on %u hop\as",hopcnt);
  if (ridcnt == 0) return info(0,"skip compound on no rids for %u hop\as",hopcnt);

  docompound = dorun(FLN,Runcompound,1);

  if (docompound == 0) return info0(0,"compound not enabled");

  info(0,"compounding %u ports %u hops max chain %u",portcnt,hopcnt,hichainlen);

  ub4 *orgportsbyhop = net->portsbyhop;
  ub4 *orghopdist = net->hopdist;

  ub4 *orghopdur = net->hopdur;
  ub4 midur,dur,sumdur,durdif;

  ub4 hop1,hop2,rhop1,rhop2,dep1,arr2;
  ub4 dist1,dist2,dist = 0,dirdist;
  ub4 tdep,tarr,tdep1,tarr2;
  ub4 ci,ci1,ci2,pchlen,cmpcnt;

  ub4 pchain[Chainlen];
  ub4 pdeps[Chainlen];
  ub4 parrs[Chainlen];
  ub4 ptdep[Chainlen];
  ub4 ptarr[Chainlen];
  ub4 pdist[Chainlen];

  error_zp(orghopdist,hopcnt);

  ub4 cnt,cmphopcnt = 0;

  error_z(chaincnt,ridcnt);

  error_zp(routes,0);
  error_zp(chains,0);

  struct eta eta;
  int warnlim;

  ub8 cumfevcnt = 0,cumcfevcnt = 0;
  ub4 cumfhops = 0;

  ub4 hicnt = 0,hirid = 0;

  for (rid = 0; rid < ridcnt; rid++) {
    rp = routes + rid;
    if (rp->hopcnt > hicnt) { hicnt = rp->hopcnt; hirid = rid; }
  }
  rp = routes + hirid;
  info(0,"r.rid %u.%u has %u hops for len %u",rp->rrid,hirid,hicnt,rp->hichainlen);
  hiportlen = max(hichainlen,hicnt) + 10;
  ub4 hiport2 = hiportlen * hiportlen;

  ub4 *port2rport = alloc(portcnt,ub4,0,"cmp rportmap",portcnt);
  ub4 *rport2port = alloc(hiportlen,ub4,0,"cmp rportmap",hiportlen);

  ub4 *duphops = alloc(hiport2,ub4,0xff,"cmp duphops",hiportlen);
  ub4 *cduphops = alloc(hiport2,ub4,0xff,"cmp cduphops",hiportlen);

  ub4 *rport2hop = alloc(hiport2,ub4,0xff,"cmp rport2hop",hiportlen);
  ub4 *rhopcdur = alloc(hiport2,ub4,0,"cmp hopcdur",newhopcnt);
  ub4 *hopccnt = alloc(hiport2,ub4,0,"cmp hopccnt",newhopcnt);

  ub4 *hoplodur = alloc(hiport2,ub4,0,"cmp hoplodur",newhopcnt);
  ub4 *hophidur = alloc(hiport2,ub4,0,"cmp hophidur",newhopcnt);

  ub4 port2 = portcnt * portcnt;
  ub4 *duprids = alloc(port2,ub4,0xff,"cmp duprids",portcnt);

  // pass 1: count
  for (rid = 0; rid < ridcnt; rid++) {
    if (progress(&eta,"compound rid %u of %u for %u chains pass 1",rid,ridcnt,chaincnt)) return 1;
    rp = routes + rid;
    rrid = rp->rrid;

    nsethi(port2rport,portcnt);
    rportcnt = 0;
    for (hop = 0; hop < hopcnt; hop++) {
      hp = hops + hop;
      if (hp->rid != rid) continue;
      dep = hp->dep; arr = hp->arr;
      if (dep == arr) continue;

      deparr = dep * portcnt + arr;
      if (duprids[deparr] == rid) {
        warn(Iter,"duplicate hop %u %u-%u for rid %u",hop,dep,arr,rid);
        continue;
      }
      duprids[deparr] = rid;

      if (hp->reserve) {
        cumfevcnt += hp->tp.evcnt;
        cumfhops++;
      }
      if (port2rport[dep] == hi32) {
        error_ge(rportcnt,hiportlen);
        port2rport[dep] = rportcnt;
        rport2port[rportcnt++] = dep;
      }
      if (port2rport[arr] == hi32) {
        error_ge_cc(rportcnt,hiportlen,"rrid %u len %u cnt %u",rrid,rp->hichainlen,rp->hopcnt);
        port2rport[arr] = rportcnt;
        rport2port[rportcnt++] = arr;
      }
    }
    warncc(rportcnt >= hiportlen,0,"r.rid %u.%u len %u above %u",rrid,rid,rportcnt,hiportlen);
    rportcnt = min(rportcnt,hiportlen);
    rport2 = rportcnt * rportcnt;
    nsethi(duphops,rport2);
    newcnt = 0;
    for (rdep = 0; rdep < rportcnt; rdep++) duphops[rdep * rportcnt + rdep] = 0;

    warnlim = 1;
    for (chain = 0; chain < chaincnt; chain++) {
      cp = chains + chain;
      cnt = cp->hopcnt;
      if (cp->rid != rid || cnt < 3) continue;

      pchlen = 0;
      for (ci = 0; ci < cnt; ci++) {
        chp = chainhops + cp->hopofs + ci;
        hop = chp->hop;
        error_ge(hop,hopcnt);

        if (pchlen == maxperm) {
          warncc(warnlim,0,"limiting rid %u chain to %u",rid,maxperm);
          warnlim = 0;
          break;
        }

        dep = orgportsbyhop[hop * 2];
        arr = orgportsbyhop[hop * 2 + 1];
        error_ge(dep,portcnt);
        error_ge(arr,portcnt);
        if (dep == arr) continue;

        rdep = port2rport[dep];
        rarr = port2rport[arr];
        error_ge(rdep,rportcnt);
        error_ge(rarr,rportcnt);

        pdeps[pchlen] = rdep;
        parrs[pchlen] = rarr;
        tdep = chp->tdep;
        tarr = chp->tarr;
        error_lt(tarr,tdep);
        pchlen++;
      }
      if (pchlen < 3) continue;

      // generate all not yet existing compounds
      memcpy(cduphops,duphops,rport2 * sizeof(*duphops));
      cmpcnt = 0;
      for (ci1 = 0; ci1 < pchlen - 1; ci1++) {
        dep1 = pdeps[ci1];
        for (ci2 = ci1 + 1; ci2 < pchlen; ci2++) {
          arr2 = parrs[ci2];
          if (dep1 == arr2) continue;
          deparr = dep1 * rportcnt + arr2;
          if (cduphops[deparr] != hi32) continue;
          duphops[deparr] = 0;
          cmpcnt++;
          if (cmpcnt >= maxperm2) break;
        } // each c2
        if (cmpcnt >= maxperm2) {
          warning(0,"limiting compound on rid %u to %u combis",rid,cmpcnt);
          break;
        }
      } // each c1
      newcnt += cmpcnt;
    } // each chain
    cmphopcnt += newcnt;
    vrb0(0,"rid %u len %u cmp %u",rid,rportcnt,newcnt);
  } // each rid
  info(0,"\ah%u compound hops added to \ah%u",cmphopcnt,hopcnt);

  if (cmphopcnt == 0) return 0;

  info(0,"compound %u chains in %u rids pass 2",chaincnt,ridcnt);

  newhopcnt = cmphopcnt + hopcnt;

  chop = hopcnt;

  ub4 *portsbyhop = alloc(newhopcnt * 2,ub4,0,"cmp portsbyhop",newhopcnt);
  memcpy(portsbyhop,orgportsbyhop,hopcnt * 2 * sizeof(ub4));
  afree(orgportsbyhop,"net portsbyhop");
  net->portsbyhop = portsbyhop;

  ub4 *hopdist = alloc(newhopcnt,ub4,0,"cmp hopdist",newhopcnt);
  memcpy(hopdist,orghopdist,hopcnt * sizeof(ub4));
  afree(orghopdist,"net hopdist");
  net->hopdist = hopdist;

  ub4 *hopdur = alloc(newhopcnt,ub4,0,"cmp hopdur",newhopcnt);
  memcpy(hopdur,orghopdur,hopcnt * sizeof(ub4));
  afree(orghopdur,"net hopdur");
  net->hopdur = hopdur;

  ub4 *hopcdur = alloc(newhopcnt,ub4,0,"cmp hopcdur",newhopcnt);

  ub4 *choporg = alloc(newhopcnt * 2,ub4,0,"cmp choporg",newhopcnt);

  ub8 cumchainlen = 0,pchaincnt = 0;
  ub4 eqdurs = 0,aeqdurs = 0;
  ub4 cdist;

  nsethi(duprids,port2);

  // pass 2
  for (rid = 0; rid < ridcnt; rid++) {
    if (progress(&eta,"compound rid %u of %u for %u chains pass 2",rid,ridcnt,chaincnt)) return 1;

    rp = routes + rid;

    nsethi(port2rport,portcnt);
    rportcnt = 0;
    for (hop = 0; hop < hopcnt; hop++) {
      hp = hops + hop;
      if (hp->rid != rid) continue;

      dep = hp->dep; arr = hp->arr;
      if (dep == arr) continue;

      deparr = dep * portcnt + arr;
      if (duprids[deparr] == rid) continue;
      duprids[deparr] = rid;

      if (port2rport[dep] == hi32) { port2rport[dep] = rportcnt; rport2port[rportcnt++] = dep; }
      if (port2rport[arr] == hi32) { port2rport[arr] = rportcnt; rport2port[rportcnt++] = arr; }
    }
    rportcnt = min(rportcnt,hiportlen);
    rport2 = rportcnt * rportcnt;
    nsethi(duphops,rport2);
    nclear(rhopcdur,rport2);
    nclear(hopccnt,rport2);

    for (chain = 0; chain < chaincnt; chain++) {
      cp = chains + chain;
      cnt = cp->hopcnt;
      if (cp->rid != rid || cnt < 3) continue;

      pchlen = 0; cdist = 0;
      for (ci = 0; ci < cnt; ci++) {
        chp = chainhops + cp->hopofs + ci;
        hop = chp->hop;

        dep = portsbyhop[hop * 2];
        arr = portsbyhop[hop * 2 + 1];
        if (dep == arr) continue;

        pdep = ports + dep;
        parr = ports + arr;

        rdep = port2rport[dep];
        rarr = port2rport[arr];
        error_ge(rdep,rportcnt);
        error_ge(rarr,rportcnt);

        for (ci2 = 0; ci2 < pchlen; ci2++) {
          hop2 = pchain[ci2];
          if (hop != hop2) continue;
          error(Exit,"rid %u chain %u hop %u pos %u equals pos %u %s to %s",rid,chain,hop,pchlen,ci2,pdep->name,parr->name);
        }
        dist = hopdist[hop];
        hp = hops + hop;
        pchain[pchlen] = hop;
        pdeps[pchlen] = rdep;
        parrs[pchlen] = rarr;
        pdist[pchlen] = cdist;
        ptdep[pchlen] = chp->tdep;
        ptarr[pchlen] = chp->tarr;
        cdist += max(dist,1);
        pchlen++;
        if (pchlen == maxperm) { warning(0,"limiting rid %u chain to %u",rid,maxperm); break; }
      }
      if (pchlen < 3) continue;

      pchaincnt++;
      cumchainlen += pchlen;

      // generate all not yet existing compounds
      // note that some chains visit ports more than once
      memcpy(cduphops,duphops,rport2 * sizeof(*duphops));
      cmpcnt = 0;
      for (ci1 = 0; ci1 < pchlen - 1; ci1++) {
        dep1 = pdeps[ci1];
        for (ci2 = ci1 + 1; ci2 < pchlen; ci2++) {
          arr2 = parrs[ci2];
          if (dep1 == arr2) continue;
          deparr = dep1 * rportcnt + arr2;
          prvda = cduphops[deparr];
          if (prvda != hi32) {  // existing: accumulate and range duration
            tdep1 = ptdep[ci1];
            tarr2 = ptarr[ci2];
            error_lt(tarr2,tdep1);
            dur = tarr2 - tdep1;
            rhopcdur[prvda] += dur;
            hoplodur[prvda] = min(hoplodur[prvda],dur);
            hophidur[prvda] = max(hophidur[prvda],dur);

            hopccnt[prvda]++;
            continue;
          }

          if (chop >= newhopcnt) {
            warn(0,"limiting compound to %u hops",chop - hopcnt);
            break;
          }

          duphops[deparr] = deparr;
          rport2hop[deparr] = chop;

          // generate compound
          hop1 = pchain[ci1];
          hop2 = pchain[ci2];
          dist1 = pdist[ci1];
          dist2 = pdist[ci2];
          tdep1 = ptdep[ci1];
          tarr2 = ptarr[ci2];

          infocc(dist2 == 0,0,"chop %u dist %u+%u",chop,dist1,dist2);

          error_eq(hop1,hop2);

          dep = rport2port[dep1];
          arr = rport2port[arr2];
          portsbyhop[chop * 2] = dep;
          portsbyhop[chop * 2 + 1] = arr;
          choporg[chop * 2] = hop1;
          choporg[chop * 2 + 1] = hop2;
          hp1 = hops + hop1;
          hp2 = hops + hop2;
          if (hp1->reserve) {
            cumcfevcnt += hp1->tp.evcnt;
            cumfhops++;
          }
          rhop1 = hp1->rhop;
          rhop2 = hp2->rhop;
          crp = chainrhops + cp->rhopofs;

          error_lt(dist2,dist1); // todo ?

          dist = dist2 - dist1 + hopdist[hop2];

          pdep = ports + dep;
          parr = ports + arr;
          dirdist = fgeodist(pdep,parr);
          hopdist[chop] = max(dist,dirdist);

          noexit error_lt(tarr2,tdep1); // todo: day wrap ?

          error_ne(crp[rhop1] >> 32,tdep1);
          error_ne(crp[rhop2] & hi32,tarr2);

          if (tarr2 >= tdep1) midur = tarr2 - tdep1;
          else midur = hi32;
          hopdur[chop] = midur;

          // first entry
          rhopcdur[deparr] = midur;
          hoplodur[deparr] = midur;
          hophidur[deparr] = midur;
          hopccnt[deparr] = 1;

          chop++;
          cmpcnt++;
        } // each c2
        if (chop >= newhopcnt) break;
        else if (cmpcnt >= maxperm2) {
          warning(0,"limiting compound on rid %u to %u combis",rid,cmpcnt);
          break;
        }
      } // each c1
      if (chop >= newhopcnt) break;
    } // each chain
    if (chop >= newhopcnt) break;

    for (deparr = 0; deparr < rport2; deparr++) {
      da = duphops[deparr];
      if (da == hi32) continue;
      hop = rport2hop[da];
      error_ge(hop,chop);

      cnt = hopccnt[da];
      error_z(cnt,hop);

      error_gt(hoplodur[da],hophidur[da],hop);
      durdif = hophidur[da] - hoplodur[da];
      sumdur = rhopcdur[da];
      if (durdif == 0) {
        dur = sumdur / cnt;
        warncc(dur > 1440 * 2,Iter,"chop %u dur %u",hop,dur);
        eqdurs++;
      } else if (durdif < 10) {
        dur = sumdur / cnt;
        warncc(dur > 1440 * 2,Iter,"chop %u dur %u",hop,dur);
        aeqdurs++;
      } else { // possible if loop in route
        hop1 = choporg[hop * 2];
        hop2 = choporg[hop * 2 + 1];
        infovrb(durdif > 30,Notty|Iter,"chop %u %u-%u dur %u-%u rid %u %s",hop,hop1,hop2,hoplodur[da],hophidur[da],rid,rp->name);
        dur = hi32;
      }
      hopcdur[hop] = dur;
      hopdur[hop] = min(hopdur[hop],dur);
    }

  } // each rid
  chopcnt = chop;

  afree(duprids,"cmp duprids");

  info(0,"\ah%u compound hops, \ah%u with constant duration, \ah%u within 10 min",chop - hopcnt,eqdurs,aeqdurs);
  info(0,"avg chain len %u",(ub4)(cumchainlen / chaincnt));

  net->chopcnt = chopcnt;
  net->choporg = choporg;
  net->hopcdur = hopcdur;

  // check if distance valid ( minimum 1 unit)
#if 1
  for (hop = 0; hop < chopcnt; hop++) {
    dep = portsbyhop[hop * 2];
    arr = portsbyhop[hop * 2 + 1];
    if (dep == arr) continue;
    dist = hopdist[hop];
    pdep = ports + dep;
    parr = ports + arr;
    if (hop < hopcnt) {
      infocc(dist == 0,0,"hop %u %u-%u \ag%u %s to %s",hop,dep,arr,dist,pdep->name,parr->name);
    } else {
      hop1 = choporg[hop * 2];
      hop2 = choporg[hop * 2 + 1];
      infocc(dist == 0,0,"chop %u = %u-%u %u-%u \ag%u %s to %s",hop,hop1,hop2,dep,arr,dist,pdep->name,parr->name);
    }
  }
#endif

  // allocate fare entries here, as they are for both plain and compound hops on reserved routes
  info(0,"\ah%lu + \ah%lu fare entries for %u hops",cumfevcnt,cumcfevcnt,cumfhops);

  cumfevcnt += cumcfevcnt;
  net->fareposcnt = cumfevcnt;

  ub4 *fhopofs = NULL;

  if (cumfhops) fhopofs = net->fhopofs = alloc(chopcnt,ub4,0xff,"fare fhopofs",cumfhops);

  ub4 *ridhops,*ridhopbase = net->ridhopbase;

  ub4 ofs = 0;
  ub4 h1ndx,h2ndx,hopndx,rhopcnt,h;
  for (hop = 0; hop < hopcnt; hop++) {
    hp = hops + hop;
    if (hp->reserve) { fhopofs[hop] = ofs; ofs += hp->tp.evcnt; }
  }
  for (chop = hopcnt; chop < chopcnt; chop++) {
    hop1 = choporg[chop * 2];
    hop2 = choporg[chop * 2 + 1];
    hp = hops + hop1;
    if (hp->reserve && fhopofs) { fhopofs[chop] = ofs; ofs += hp->tp.evcnt; }
    rid = hp->rid;
    rp = routes + rid;
    rhopcnt = rp->hopcnt;
    hopndx = 0; h1ndx = h2ndx = hi32;
    ridhops = ridhopbase + rp->hop2pos;
    while (hopndx < min(rhopcnt,Chainlen) && (h1ndx == hi32 || h2ndx == hi32)) {
      h = rp->hops[hopndx];
      if (h == hop1) h1ndx = hopndx;
      else if (h == hop2) h2ndx = hopndx;
      hopndx++;
    }
    if (h1ndx == hi32 || h2ndx == hi32) {
      vrb0(0,"rid %u hop %u-%u not found at %u-%u chop %u",rid,hop1,hop2,h1ndx,h2ndx,chop);
      continue;
    }
    error_ge(h1ndx,rhopcnt);
    error_ge(h2ndx,rhopcnt);
    ridhops[h1ndx * rhopcnt + h2ndx] = chop;
  }

  if (cumfhops) net->fareposbase = mkblock(&net->faremem,cumfevcnt * Faregrp,ub2,Init0,"fare entries for %u reserved hops",cumfhops);

  return 0;
}