// Modest model for the IEEE 802.3 CSMA/CD protocol
action send, send1, send2;
action end, end1, end2;
action busy, busy1, busy2;
action cd, cd1, cd2;
action csend;
action counted;

const int RED = 2; // reduction factor
const int PD = (int)(26 / RED); // signal propagation delay
const int TD = (int)(808 / RED); // packet transmission delay
const int ST = 2 * PD; // backoff time slot length
const int BCMAX = 2; // 2 or 4
const int n;

// Properties
property D_max = Pmax(<> did(counted));

process Medium()
{
   clock c1;
   clock c2;

   do {
      :: alt { :: send1 {= c1=0 =} :: send2 {= c2=0 =} };
         do {
            :: alt { :: end1 {= c1=0 =} :: end2 {= c2=0 =} }; // transfer finished
               urgent break
            :: alt { :: when(c2 <= PD) send1 {= c1=0 =} :: when(c1 <= PD) send2 {= c2=0 =} }; csend; // collision
               invariant(c1 <= PD && c2 <= PD) 
               alt {
                   :: when(c1 >= PD) cd1 {= c1=0 =}; invariant(c2 <= PD) when(c2 >= PD) cd2 {= c2=0 =}
                   :: when(c2 >= PD) cd2 {= c2=0 =}; invariant(c1 <= PD) when(c1 >= PD) cd1 {= c1=0 =}
               };
               urgent break
            :: when(c1 >= PD) busy2 // carrier is sensed busy
            :: when(c2 >= PD) busy1 // carrier is sensed busy
         }
   }
}

process Station()
{
  clock c;
  int bc limit [0..BCMAX];
  int backoff limit [1..pow(2, BCMAX)];

  when(c <= PD) send {= c=0 =}; //model on internet has no invariant, but is really needed also in model.h
  do {
    :: invariant(c <= TD)
    alt {
      :: when(c == TD) end {= c=0 =};
      urgent break
      :: cd {= c=0, bc=min(bc + 1, BCMAX) =}; //increment bc but not more than BCMAX  
      do {
        :: urgent {= backoff=DiscreteUniform(1, pow(2, bc)) =};
        invariant(c <= backoff * ST) when(c == backoff * ST)
        alt { //ALSO RESET of backoff variable when if is dead helps some 5 seconds
          :: send {= c=0, backoff=1 =}; urgent break
          :: busy {= c=0, backoff=1, bc=min(bc + 1, BCMAX) =} //increment bc but not more than BCMAX
        }
      }
    }
  }
}

process Counter()
{
  int counter limit [0..n+1];
  do {
    :: csend {= counter=min(n+1,counter+1) =}
    :: when(counter == n) counted
  }
}

par {
   :: Medium()
   :: relabel { send, end, busy, cd } by { send1, end1, busy1, cd1 } Station()
   :: relabel { send, end, busy, cd } by { send2, end2, busy2, cd2 } Station()
   :: Counter()
}
