Advertisement
Guest User

Untitled

a guest
Mar 27th, 2019
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 8.76 KB | None | 0 0
  1. defmodule Elevatorm do
  2.   @moduledoc """
  3.  This is the Elevator module
  4.  """
  5.   def start_working do
  6.     IO.puts("I am listening with pid #{inspect(self())}")
  7.  
  8.     receive do
  9.       {:ok, pid_distributor, _} ->
  10.         IO.puts("Empty list received from distributor #{inspect(pid_distributor)}")
  11.         # setup driver connection
  12.         {:ok, pid_driver} = Driver.start()
  13.         IO.puts("Driver connected")
  14.         # connect_FSM()
  15.         {:ok, pid_FSM} = ElevatorFSM.start_link()
  16.         IO.puts("FSM started")
  17.         go_to_know_state(pid_FSM, pid_driver, pid_distributor)
  18.         retrieve_local_backup(self(), pid_FSM, pid_driver, pid_distributor)
  19.         IO.puts("Spawn collectors")
  20.         pid_elevator = self()
  21.         ElevatorFSM.send_status(pid_FSM, pid_distributor, pid_elevator)
  22.  
  23.         pid_order_collector =
  24.           spawn(fn -> ElevatorFSM.order_collector(pid_elevator, pid_driver, pid_distributor) end)
  25.  
  26.         pid_floor_collector =
  27.           spawn(fn ->
  28.             ElevatorFSM.floor_collector(pid_elevator, pid_driver, pid_distributor, pid_FSM)
  29.           end)
  30.  
  31.         IO.puts("Entering receiving loop")
  32.         IO.puts("======================================")
  33.         IO.puts("DISTRIBUTOR      #{inspect(pid_distributor)}")
  34.         IO.puts("DRIVER           #{inspect(pid_driver)}")
  35.         IO.puts("FSM_ELEVATOR     #{inspect(pid_FSM)}")
  36.         IO.puts("ELEVATOR         #{inspect(pid_elevator)}")
  37.         IO.puts("ORDER COLLECTOR  #{inspect(pid_order_collector)}")
  38.         IO.puts("FLOOR COLLECTOR  #{inspect(pid_floor_collector)}")
  39.         IO.puts("======================================")
  40.         all_pids=[pid_order_collector,pid_floor_collector,pid_FSM, pid_driver]
  41.         receive_orders_loop(pid_distributor, pid_FSM, pid_driver,all_pids)
  42.       message ->
  43.         IO.puts(
  44.           "Error elevator module: unexpected message before initialization #{inspect(message)}"
  45.         )
  46.     end
  47.   end
  48.  
  49.   def receive_orders_loop(pid_distributor, pid_FSM, pid_driver, all_pids) do
  50.     receive do
  51.       {:ok, pid, :harakin} ->
  52.         Enum.map(all_pids, fn pid -> Process.exit(pid, :kill) end)
  53.         IO.puts "Bye ;( "
  54.         Process.exit(self(), :kill)
  55.       {:ok, pid_sender, complete_system} ->
  56.         IO.puts("Complete system received #{inspect(complete_system)}")
  57.  
  58.         if pid_sender != pid_distributor do
  59.           IO.puts("I am receiving a complete_system from an unexpected distributor")
  60.         end
  61.  
  62.         store_local_backup(complete_system)
  63.         {state, _floor, _movement} = ElevatorFSM.get_state(pid_FSM)
  64.         ip = get_my_local_ip()
  65.         my_elevator = Enum.find(complete_system, fn elevator -> elevator.ip == ip end)
  66.  
  67.         if state == :IDLE do
  68.           if my_elevator.orders != [] do
  69.             order = List.first(my_elevator.orders).floor
  70.             sender = self()
  71.             spawn(fn -> elevator_loop(sender, pid_FSM, pid_driver, pid_distributor, order) end)
  72.             ElevatorFSM.send_status(pid_FSM, pid_distributor, self())
  73.           end
  74.         end
  75.  
  76.         light_orders = my_elevator.lights
  77.  
  78.         if light_orders != [] do
  79.           IO.puts("----- HANDLE LIGHTS #{inspect(light_orders)}")
  80.           Enum.map(light_orders, fn x -> action_light(x, pid_driver) end)
  81.         end
  82.     after
  83.       9_000 -> IO.puts("No orders received after 9 seconds")
  84.     end
  85.  
  86.     receive_orders_loop(pid_distributor, pid_FSM, pid_driver)
  87.   end
  88.  
  89.   def elevator_loop(sender, pid_FSM, pid_driver, pid_distributor, order) do
  90.     ElevatorFSM.new_order(pid_FSM, pid_driver, order)
  91.  
  92.     {_state, current_floor, _movement} = ElevatorFSM.get_state(pid_FSM)
  93.  
  94.     if current_floor == order do
  95.       ElevatorFSM.arrived(pid_FSM, pid_driver)
  96.       ElevatorFSM.send_status(pid_FSM, pid_distributor, sender)
  97.       open_doors(pid_driver)
  98.       ElevatorFSM.continue_working(pid_FSM)
  99.       ElevatorFSM.send_status(pid_FSM, pid_distributor, sender)
  100.       :timer.sleep(100)
  101.       Process.exit(self(), :kill)
  102.     end
  103.  
  104.     ElevatorFSM.update_floor(pid_FSM, pid_driver)
  105.     :timer.sleep(100)
  106.     elevator_loop(sender, pid_FSM, pid_driver, pid_distributor, order)
  107.   end
  108.  
  109.   ###############################################################################
  110.   ###############################################################################
  111.   ###############################################################################
  112.   @doc """
  113.    Moves the elevator to a known state in the case that the elevator is
  114.    not exciting any floor sensor.
  115.  """
  116.   def go_to_know_state(pid_FSM, pid_driver, pid_distributor) do
  117.     IO.puts("Moving to know state")
  118.  
  119.     if Driver.get_floor_sensor_state(pid_driver) == :between_floors do
  120.       {_state, _floor, movement} = ElevatorFSM.get_state(pid_FSM)
  121.  
  122.       if movement != :down do
  123.         ElevatorFSM.set_status(pid_FSM, :MOVE, :unspecified, :down)
  124.         Driver.set_motor_direction(pid_driver, :down)
  125.       end
  126.  
  127.       go_to_know_state(pid_FSM, pid_driver, pid_distributor)
  128.     else
  129.       Driver.set_motor_direction(pid_driver, :stop)
  130.       floor = Driver.get_floor_sensor_state(pid_driver)
  131.       ElevatorFSM.set_status(pid_FSM, :IDLE, floor, :idle)
  132.       ElevatorFSM.send_status(pid_FSM, pid_distributor, self())
  133.       :ok
  134.     end
  135.   end
  136.  
  137.   @doc """
  138.    Tries to open the backup file and, if it exists, move the elevator to the
  139.    previous status that was stored in the backup. It also send the backup file
  140.    to the
  141.  """
  142.   def retrieve_local_backup(sender, pid_FSM, pid_driver, pid_distributor) do
  143.     case File.read("local_backup") do
  144.       {:ok, data} ->
  145.         IO.puts("
  146.        £££££££££££££££££££££££££££££££££££££££££££££££££
  147.        £  There is a backup avalible
  148.        £££££££££££££££££££££££££££££££££££££££££££££££££
  149.         ")
  150.         complete_system = :erlang.binary_to_term(data)
  151.         IO.puts("Complete system retrieved : #{inspect(complete_system)}")
  152.         IO.puts("Sending backup the complete system to the distributor")
  153.         send(pid_distributor, {:complete_list, sender, complete_system})
  154.  
  155.       {:error, :enoent} ->
  156.         IO.puts("
  157.         ££££££££££££££££££££££££££££££££££££££££££££££££££
  158.         £  There is no backup, lets create one
  159.         ££££££££££££££££££££££££££££££££££££££££££££££££££
  160.         ")
  161.         complete_system = CreateList.init_list_fake(get_my_local_ip(), self())
  162.         IO.puts("Complete system retrieved : #{inspect(complete_system)}")
  163.         IO.puts("Sending backup the complete system to the distributor")
  164.         send(pid_distributor, {:complete_list, sender, complete_system})
  165.  
  166.       unspected ->
  167.         IO.puts("Unespected read result : #{inspect(unspected)}")
  168.     end
  169.   end
  170.  
  171.   def get_orders(_list) do
  172.     # ==========================================================================
  173.     # TO DO: Handle the receive from the distributor keeping the complete
  174.     # list of orders
  175.     receive do
  176.       {:complete_system, complete_system} ->
  177.         store_local_backup(complete_system)
  178.         List.first(complete_system).ip
  179.     after
  180.       # notify_observer()
  181.       5_000 -> IO.puts("Notify observer")
  182.     end
  183.   end
  184.  
  185.   @doc """
  186.    Turn on the "door opened" light for 3 seconds. It is important to note that
  187.    the code running blocks when calling this for 3 seconds.
  188.  """
  189.   def open_doors(pid_driver) do
  190.     Driver.set_door_open_light(pid_driver, :on)
  191.     :timer.sleep(3000)
  192.     Driver.set_door_open_light(pid_driver, :off)
  193.   end
  194.  
  195.   @doc """
  196.    This function stores the status of the complete system using the file
  197.    library. It either create a new file in the same folder that this module or
  198.    overwrite the existing one. In order to store complex structures and lists
  199.    the conversion of the Erlang library term_to_binary is conducted. It is
  200.    important to reconvert it to term using binary_to_term to recover the same
  201.    data structure.
  202.  """
  203.   def store_local_backup(complete_system) do
  204.     {:ok, file} = File.open("local_backup", [:write])
  205.     IO.binwrite(file, :erlang.term_to_binary(complete_system))
  206.     File.close(file)
  207.   end
  208.  
  209.   @doc """
  210.    This function returns the value of the local IP adrres. It works both in
  211.    Windows and Ubuntu.
  212.  """
  213.   def get_my_local_ip do
  214.     case :inet.getif() do
  215.       {:ok, [{ip, _defini1, _mask1}, {_nope, _defini, _mask2}]} -> ip
  216.       {:ok, [_none1, {ip, _none2, _none3}, _none4]} -> ip
  217.     end
  218.   end
  219.  
  220.   def pid(string) when is_binary(string) do
  221.     :erlang.list_to_pid('<#{inspect(string)}>')
  222.   end
  223.  
  224.   def action_light(light, pid) do
  225.     IO.puts("Set light: #{inspect(light)}")
  226.     Driver.set_order_button_light(pid, light.type, light.floor, light.state)
  227.   end
  228. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement