//-------------------------------------------------------------
// File: HcubeRte.cc
//
// Implementation of simple module types
//
// Authors: Andras Varga (TU Budapest)
//-------------------------------------------------------------

#include <stdio.h>
#include <omnetpp.h>
#include "hc_rte.h"
#include "hcpacket_m.h"

#define TRACE_MSG

#define SLOT_TIME   1.0
#define PROPDEL     (0.99*SLOT_TIME)

// Module registration:
Define_Module( HCRouter )

void deflectionRouting(int my_address,int dim,
                       int *rte_dest, int num_rte, int *rte_port,
                       int *usr_dest, int num_usr, int *usr_port);

//
// Activity of the simple module
//
void HCRouter::activity()
{
   int my_address = par("address");
   int dim = par("dim");
   int fromUserGateId = gate("from_gen")->id();
   long total_usr = 0, discarded_usr = 0;

   cMessage *endOfSlot = new cMessage("endOfSlot");
   for(;;)
   {
      int i;

      // buffers for transit cells (rte) and for cells from local user (usr)
      HCPacket *rte_cell[32];
      int num_rte = 0;
      HCPacket *usr_cell[32];
      int num_usr = 0;

      // collect cells; user cells go into separate buffer
      scheduleAt( simTime()+SLOT_TIME, endOfSlot );
      cMessage *msg;
      while ((msg=receive())!=endOfSlot)
      {
         HCPacket *pkt = check_and_cast<HCPacket *>(msg);
         if (pkt->arrivalGateId()!=fromUserGateId)
         {
            if (pkt->getDestAddress()!=my_address)
               rte_cell[num_rte++] = pkt;
            else
               send(pkt,"to_sink");
         }
         else
         {
            total_usr++;
            if (num_usr<32)
               usr_cell[num_usr++] = pkt;
            else
               {discarded_usr++; delete pkt;}
         }
      }

      // prepare arrays used in routing
      int rte_dest[32], rte_port[32]; // destinations, output ports
      int usr_dest[32], usr_port[32];
      for (i=0;i<num_rte;i++) rte_dest[i] = rte_cell[i]->getDestAddress();
      for (i=0;i<num_usr;i++) usr_dest[i] = usr_cell[i]->getDestAddress();

      // make routing decision (function fills rte_port[] and usr_port[])
      deflectionRouting(my_address, dim,
                        rte_dest, num_rte, rte_port,
                        usr_dest, num_usr, usr_port);

      // send out transit cells
      for (i=0; i<num_rte; i++)
      {
         rte_cell[i]->setHops(rte_cell[i]->getHops()+1);
         sendDelayed(rte_cell[i], PROPDEL, "out", rte_port[i]);
      }

      // send out user cells
      for (i=0; i<num_usr; i++)
      {
         if (usr_port[i]<0)
         {
            discarded_usr++;
            delete usr_cell[i];
         }
         else
         {
            usr_cell[i]->setHops(usr_cell[i]->getHops()+1);
            sendDelayed(usr_cell[i], PROPDEL, "out", usr_port[i]);
         }
      }
      ev.printf("rte[%d]: Discarded %ld out of %ld\n", my_address, discarded_usr, total_usr);
   }
}


void deflectionRouting(int my_address,int dim,
                       int *rte_dest, int num_rte, int *rte_port,
                       int *usr_dest, int num_usr, int *usr_port)
{
   // This function implements a simple, fast, but very suboptimal, unfair,
   // unbalanced etc. deflection scheme.
   int i;

   unsigned port_mask = (1<<dim)-1;

   // used_ports: bits set to 1 will denote ports already assigned
   unsigned used_ports = 0;

   // assign transit cells to ports
   for (i=0;i<num_rte;i++)
   {
      unsigned optimal = my_address ^ rte_dest[i];
      unsigned usable = optimal & ~used_ports & port_mask;

      if (usable)
      {
         // route through first usable port (with smallest index)
         int k;
         for (k=0; (usable & (1<<k))==0; k++);
         rte_port[i] = k;
         used_ports |= 1<<k;
      }
      else
      {
         // deflect through first free port (with smallest index)
         int k;
         for (k=0; used_ports & (1<<k); k++);
         rte_port[i] = k;
         used_ports |= 1<<k;
      }
   }

   // assign user cells to remaining ports
   for (i=0;i<num_usr;i++)
   {
      unsigned optimal = my_address ^ usr_dest[i];
      unsigned usable = optimal & ~used_ports & port_mask;

      if (usable)
      {
         // route through first usable port (with smallest index)
         int k;
         for (k=0; (usable & (1<<k))==0; k++);
         usr_port[i] = k;
         used_ports |= 1<<k;
      }
      else if (used_ports!=port_mask)
      {
         // deflect through first free port (with smallest index)
         int k;
         for (k=0; used_ports & (1<<k); k++);
         usr_port[i] = k;
         used_ports |= 1<<k;
      }
      else
      {
         // all ports used, cell will be discarded
         usr_port[i] = -1;
      }
   }

}


syntax highlighted by Code2HTML, v. 0.9.1