Traffic Lights Subroutine example

This version of the Traffic Lights example uses a subroutine transaction to decide whether the pedestrian crossing button was pushed. If it was, the traffic lights in the junction change for a short period to allow for pedestrian crossing. The junction and the button are both represented as stateful svc_expr services.

Figure: Traffic Lights Subroutines example - The mix


Tip: Get the code from the SPARKL public repository.
Table 1. Traffic Lights Subroutines example - The markup
Markup Explanation
<folder name="Traf_Lig_Subr">
  <service name="Junction" 
    provision="expr">
    <prop name="expr.state" 
      PedLight="NewPedLight" 
      TrafLight="NewTrafLight"/>
    <prop name="expr.init" 
      PedLight="red" 
      TrafLight="green"/>
  </service>
  <service name="Sequencer"
    provision="sequencer"/>
  <folder name="MasterFolder">
    <field name="PEOPLE"/>
    <field name="START"/>
    <field name="TRAFFIC"/>
    <service name="Master" 
      provision="subr">
      <prop name="subr.import" 
        key="SubrKey"/>
    </service>
    <mix name="MasterMix">
      ...
    </mix>
  </folder>
  <folder name="SubrFolder">
    <field name="MODE"/>
    <field name="NO"/>
    <field name="YES"/>
    <field name="PRESS"/>
    <service name="Subr" 
      provision="subr">
      <prop name="subr.export" 
        key="SubrKey"/>
    </service>
    <mix name="SubrMix">
      ...
    </mix>
  </folder>
</folder>
This example comprises:
  • Junction, a service provisioned using the Expressions extension
  • Two folders, MasterFolder and SubrFolder, which both contain a number of fields, services and operations
Junction has two state variables:
  • PedLight - initialised to red and updated by NewPedLight
  • TrafLight - initialised to green and updated by NewTrafLight
These variables represent the traffic lights - one for pedestrians, one for cars.

MasterFolder and SubrFolder both contain a service provisioned using the Subroutine extension:

  • MasterFolder contains the Master service
  • SubrFolder contains the Subr service

The services use the subr.import and subr.export property pairs with matching keys.

Thus, Master can import and use the operations on Subr.

See:

  • Table 2 on the operations in MasterMix
  • Table 3 on the operations in SubrMix
Table 2. Traffic Lights Subroutines example - The master mix
Markup Explanation
<mix name="MasterMix">
  <notify name="Start" 
    service="Sequencer" 
    clients="Junction" 
    fields="START">
    <prop name="expr.auto" 
      interval="15s"/>
  </notify>
  <folder name="Get">
    ...
  </folder>
  <folder name="Set">
    ...
  </folder>
</mix>
MasterMix comprises:
  • Start, a notify operation
  • Two subfolders - Get and Set - containing other operations
The Start notify is triggered by the Junction service and implemented by the Sequencer service.

Due to the expr.auto property, the operation is triggered every 15 seconds, as long as Junction is in started state.

Since it has no firing conditions, Start is fired every time it is triggered, starting a transaction every 15 seconds, as long as Junction is up and running.

<folder name="Get">
  <request name="GetMode" 
    service="Master" 
    fields="START">
    <prop name="subr.spec" 
      function="ModeFun"/>
    <reply name="People" 
      fields="PEOPLE"/>
    <reply name="Traffic" 
      fields="TRAFFIC"/>
  </request>
</folder>
The GetMode request expects the START field and sends either the People or the Traffic reply.

To choose between the replies, GetMode calls a subroutine solicit. Since it is on the Master service, GetMode can call any subroutine solicit that:

  • Is on the Subr service, which exports its operations to Master
  • Specifies the same function as GetMode
  • Has two responses with the same names as the replies
The SubrGetMode solicit meets all these requirements.
Note: Since all the fields of both GetMode and SubrGetMode are FLAGs, the fields do not have to be bound to parameters.
<folder name="Set">
  <consume name="SetPeople" 
    service="Junction" 
    fields="PEOPLE">
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
NewTrafLight = red,
NewPedLight = green.
    ]]></prop>
  </consume>
  <consume name="SetTraffic" 
    service="Junction" 
    fields="TRAFFIC">
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
NewTrafLight = green,
NewPedLight = red.
    ]]></prop>
  </consume>
</folder>
SetPeople and SetTraffic are both consume operations implemented by the Junction service.

Depending on the reply sent by GetMode, only one of the consumes is satisfied.

Whenever one of the consumes is satisfied:
  • The master transaction started by the Start operation ends
  • The states of Junction are updated:
    • SetPeople sets TrafLight to red and PedLight to green
    • SetTraffic sets TrafLight to green and PedLight to red
Table 3. Traffic Lights Subroutines example - The subroutine mix
Markup Explanation
<mix name="SubrMix">
  <service name="Button" 
    provision="expr">
    <prop name="expr.state" 
      PersonWaiting="NewPersonWaiting"/>
    <prop name="expr.init" 
      PersonWaiting="false"/>
  </service>
  <folder name="SubrGet">
    ...
  </folder>
  <folder name="Manual">
    ...
  </folder>
</mix>
The SubrMix comprises:
  • Button, a service provisioned using the Expressions extension
  • Two subfolders - SubrGet and Manual - containing operations
Button has a state variable - PersonWaiting. It is initialised to false and can be updated by the NewPersonWaiting variable.

Button represents the pedestrian crossing button.

<folder name="SubrGet">
  <solicit name="SubrGetMode" 
    service="Sequencer" 
    clients="Subr" 
    fields="MODE">
    <prop name="subr.spec" 
      function="ModeFun"/>
    <response name="People" 
      fields="YES"/>
    <response name="Traffic" 
      fields="NO"/>
  </solicit>
  <request name="IsPersonWaiting" 
    service="Button" 
    fields="MODE">
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
case PersonWaiting of
  true ->
    NewPersonWaiting = false,
    "Yes";
  false ->
    "No"
 end.
    ]]></prop>
    <reply name="Yes" 
      fields="YES"/>
    <reply name="No" 
      fields="NO"/>
  </request>
</folder>
SubrGetMode is a subroutine solicit called by the GetMode request operation.

Whenever it is called, SubrGetMode fires the MODE field starting a new subroutine transaction.

This transaction concludes when either the People or the Traffic response is sent.

IsPersonWaiting, a request operation is invoked to help in collecting either the YES or the NO field, which is needed by the responses.

IsPersonWaiting is implemented by the Button service. The expression in this operation decides which reply is to be sent. The decision is based on the state of the Button service:

  • If PersonWaiting is true, the Yes reply is sent
  • If PersonWaiting is false, the No reply is sent
Whenever the IsPersonWaiting request sends the Yes reply, the state of the Button service is reset to false.

The state can be set to true by the IsPressed operation, which represents the action of pushing the pedestrian crossing button.

<folder name="Manual">
  <consume name="IsPressed" 
    service="Button" 
    fields="PRESS">
    <prop name="expr.src" 
      content-type="text/x-erlang"><![CDATA[
NewPersonWaiting = true.
    ]]></prop>
  </consume>
</folder>
IsPressed is a consume operation implemented by the Button service.

IsPressed changes the state of Button - setting PersonWaiting to true.

In the next 15-second window when the Start operation is fired, the following happens:

  1. SubrGetMode sends the People response due to the Yes reply by IsPersonWaiting
  2. GetMode sends the People reply due to the response by SubrGetMode
  3. The People reply that carries the PEOPLE field satisfies the SetPeople consume
  4. SetPeople sets the states of Junction:
    • PedLight to green
    • TrafLight to red
Tip: Control the pedestrian crossing button from the master mix too. To do that:
  1. Create a consume in MasterMix
  2. Create a subroutine notify in SubrMix, which is called by the consume
  3. Specify PRESS as the output field of the subroutine notify