summaryrefslogtreecommitdiff
path: root/docs/examples/pilib/mobilePhoneProtocol.scala
blob: e8c0ac1dc4e30f83de9770e6f47d937850a61f26 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package examples.pilib

/**
* Mobile phone protocol.
* Equivalent to a three-place buffer.
* @see Bjoern Victor "A verification tool for the polyadic pi-calculus".
*/
object mobilePhoneProtocol {

  import concurrent.pilib._

  val random = new java.util.Random()

  // Internal messages exchanged by the protocol.
  trait Message

  // Predefined messages used by the protocol.
  case class Data()   extends Message;
  case class HoCmd()  extends Message; // handover command
  case class HoAcc()  extends Message; // handover access
  case class HoCom()  extends Message; // handover complete
  case class HoFail() extends Message; // handover fail
  case class ChRel()  extends Message; // release
  case class Voice(s: String) extends Message; // voice 
  case class Channel(n: Chan[Message]) extends Message; // channel

  def MobileSystem(in: Chan[String], out: Chan[String]): unit = {

    def CC(fa: Chan[Message], fp: Chan[Message], l: Chan[Channel]): unit =
      choice (
        in * (v => { fa.write(Data()); fa.write(Voice(v)); CC(fa, fp, l) })
        ,
        l * (m_new => {
          fa.write(HoCmd());
          fa.write(m_new);
          choice (
            fp * ({ case HoCom() => {
              System.out.println("Mobile has moved from one cell to another");
              fa.write(ChRel());
              val Channel(m_old) = fa.read;
              l.write(Channel(m_old));
              CC(fp, fa, l)
            }})
            ,
            fa * ({ case HoFail() => {
              System.out.println("Mobile has failed to move from one cell to another");
              l.write(m_new);
              CC(fa, fp, l)
            }})
          )
        })
      );

    /*
    * Continuously orders the MSC to switch the MS to the non-used BS.
    */
    def HC(l: Chan[Channel], m: Chan[Message]): unit = {
      Thread.sleep(1 + random.nextInt(1000));
      l.write(Channel(m));
      val Channel(m_new) = l.read;
      HC(l, m_new)
    }

    /**
    * Mobile switching center.
    */
    def MSC(fa: Chan[Message], fp: Chan[Message], m: Chan[Message]): unit = {
      val l = new Chan[Channel];
      spawn < HC(l, m) | CC(fa, fp, l) >
    }

    /**
    * Active base station.
    */
    def BSa(f: Chan[Message], m: Chan[Message]): unit =
      (f.read) match {
        case Data() => {
          val v = f.read;
          m.write(Data());
          m.write(v);
          BSa(f, m)
        }
        case HoCmd() => {
          val v = f.read;
          m.write(HoCmd());
          m.write(v);
          choice (
            f * ({ case ChRel() => {
              f.write(Channel(m));
              BSp(f, m)
            }})
            ,
            m * ({ case HoFail() => {
              f.write(HoFail());
              BSa(f, m)
            }})
          )
        }
      };

    /**
     * Passive base station.
     */
    def BSp(f: Chan[Message], m: Chan[Message]): unit = {
      val HoAcc = m.read
      f.write(HoCom())
      BSa(f, m)
    }

    /**
     * Mobile station.
     */
    def MS(m: Chan[Message]): unit =
      (m.read) match {
        case Data() => {
          val Voice(v) = m.read;
          out.write(v);
          MS(m)
        }
        case HoCmd() =>
          (m.read) match {
            case Channel(m_new) => {
              if (random.nextInt(1) == 0)
                choice ( m_new(HoAcc()) * (MS(m_new)) );
              else
                choice ( m(HoFail()) * (MS(m)) );
            }
          }
      };

    def P(fa: Chan[Message], fp: Chan[Message]): unit = {
      val m = new Chan[Message];
      spawn < MSC(fa, fp, m) | BSp(fp, m) >
    }

    def Q(fa: Chan[Message]): unit = {
      val m = new Chan[Message];
      spawn < BSa(fa, m) | MS(m) >
    }

    val fa = new Chan[Message];
    val fp = new Chan[Message];
    spawn < Q(fa) | P(fa, fp) >;
  }

  //***************** Entry function ******************//
  
  def main(args: Array[String]): unit = {
    
    def Producer(n: Int, put: Chan[String]): unit = {
      Thread.sleep(1 + random.nextInt(1000));
      val msg = "object " + n;
      put.write(msg);
      System.out.println("Producer gave " + msg);
      Producer(n + 1, put)
    }
    
    def Consumer(get: Chan[String]): unit = {
      Thread.sleep(1 + random.nextInt(1000));
      val msg = get.read;
      System.out.println("Consumer took " + msg);
      Consumer(get)
    }
    
    val put = new Chan[String];
    val get = new Chan[String];
    spawn < Producer(0, put) | Consumer(get) | MobileSystem(put, get) >
  }

}