Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/elevator/communicator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ defmodule Elevator.Communicator do
# Delete node from status map on disconnect
@impl true
def handle_info({:nodedown, node}, peer_status_map) do
{:noreply, %{peer_status_map | connected_nodes: Map.delete(peer_status_map, node)}}
{:noreply, Map.delete(peer_status_map, node)}
end

# Calls --------------------------------------------------
Expand Down
31 changes: 23 additions & 8 deletions lib/elevator/fsm/state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule Elevator.FSM.State do
defstruct behavior: :moving,
between_floors: true,
direction: :down,
door_open_time_ms: Time.utc_now(),
door_open_time: Time.utc_now(),
floor: :unknown,
last_floor_time: Time.utc_now(),
motor_timed_out: false,
Expand All @@ -26,7 +26,7 @@ defmodule Elevator.FSM.State do
between_floors: boolean(),
obstructed: boolean(),
motor_timed_out: boolean(),
door_open_time_ms: Time.t(),
door_open_time: Time.t(),
last_floor_time: Time.t()
}

Expand Down Expand Up @@ -85,15 +85,16 @@ defmodule Elevator.FSM.State do
# Casts --------------------------------------------------

@impl true
def handle_cast({:set_floor, floor}, state) do
def handle_cast({:set_floor, new_floor}, state) do
new_state =
case floor do
case new_floor do
:between_floors ->
%{state | between_floors: true}

_ ->
%{state | between_floors: false, floor: floor, last_floor_time: Time.utc_now()}
floor ->
%{state | between_floors: false, floor: floor}
end
|> detect_and_update_last_floor_time(state)

{:noreply, new_state}
end
Expand All @@ -111,7 +112,11 @@ defmodule Elevator.FSM.State do

@impl true
def handle_cast({:set_behavior, behavior}, state) do
{:noreply, %{state | behavior: behavior}}
new_state =
%{state | behavior: behavior}
|> detect_and_update_last_floor_time(state)

{:noreply, new_state}
end

@impl true
Expand All @@ -120,7 +125,7 @@ defmodule Elevator.FSM.State do
if state.between_floors do
state
else
%{state | behavior: :door_open, door_open_time_ms: Time.utc_now()}
%{state | behavior: :door_open, door_open_time: Time.utc_now()}
end

{:noreply, new_state}
Expand All @@ -143,4 +148,14 @@ defmodule Elevator.FSM.State do
def handle_call(:operational?, _from, state) do
{:reply, not (state.motor_timed_out or state.obstructed), state}
end

@spec detect_and_update_last_floor_time(t(), t()) :: t()
defp detect_and_update_last_floor_time(new_state, old_state) do
if old_state.between_floors != new_state.between_floors or
(old_state.behavior != :moving and new_state.behavior == :moving) do
%{new_state | last_floor_time: Time.utc_now()}
else
new_state
end
end
end
7 changes: 5 additions & 2 deletions lib/elevator/fsm/transition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,16 @@ defmodule Elevator.FSM.Transition do
defp decide_and_update_state(_state, _orders), do: :ok

defp check_motor_timeout(state) do
timed_out = Time.diff(Time.utc_now(), state.last_floor_time, :millisecond) > @motor_timeout_ms
timed_out =
state.behavior == :moving and
Time.diff(Time.utc_now(), state.last_floor_time, :millisecond) > @motor_timeout_ms

State.set_motor_timed_out(timed_out)
end

defp check_door_timer(state) when state.behavior == :door_open do
timed_out =
Time.diff(Time.utc_now(), state.door_open_time_ms, :millisecond) >
Time.diff(Time.utc_now(), state.door_open_time, :millisecond) >
Elevator.door_open_duration_ms()

cond do
Expand Down
6 changes: 3 additions & 3 deletions lib/elevator/hall_orders.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ defmodule Elevator.HallOrders do

@impl true
def handle_call(:get_handling_orders, _from, order_map) do
confirmed_orders =
handling_orders =
Enum.filter(order_map, &match?({_, {:handling, _}}, &1))
|> orders_by_floor()

{:reply, confirmed_orders, order_map}
{:reply, handling_orders, order_map}
end

@impl true
Expand Down Expand Up @@ -184,7 +184,7 @@ defmodule Elevator.HallOrders do

# Return the orders where we have the lowest cost among serving nodes.
# Only consider orders where all serving nodes have a cost.
@spec my_orders_from_order_map(hall_order_map()) :: %{floor() => MapSet.t(hall_button())}
@spec my_orders_from_order_map(hall_order_map()) :: %{floor() => MapSet.t(hall_button_type())}
defp my_orders_from_order_map(order_map) do
who_can_serve = Communicator.who_can_serve()

Expand Down
4 changes: 2 additions & 2 deletions lib/elevator/hall_orders/cost.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ defmodule Elevator.HallOrders.Cost do
@type cost_map :: Elevator.HallOrders.hall_order_cost_map()

@doc """
Comupte the cost (time to serve) of a candidate hall order by simulating single elevator logic.
Compute the cost (time to serve) of a candidate hall order by simulating single elevator logic.
"""
@spec compute_cost({floor(), hall_button_type()}, %{floor() => MapSet.t(hall_button_type())}) ::
non_neg_integer()
Expand Down Expand Up @@ -53,7 +53,7 @@ defmodule Elevator.HallOrders.Cost do
Returns if we are supposed to take the order given the cost map.
Assumes who_can_serve is a subset of cost_map keys.
"""
@spec assigned_to_me?(cost_map(), MapSet.t(node())) :: node()
@spec assigned_to_me?(cost_map(), MapSet.t(node())) :: boolean()
def assigned_to_me?(cost_map, who_can_serve) do
{min_node, _} =
Enum.filter(cost_map, fn {node, _} -> MapSet.member?(who_can_serve, node) end)
Expand Down
1 change: 1 addition & 0 deletions lib/elevator/hall_orders/order.ex
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ defmodule Elevator.HallOrders.Order do

def update_from_button_press(order_state), do: order_state

@spec update_from_button_press(hall_order_state()) :: hall_order_state()
def update_from_arrived_at_floor({:handling, _}) do
ensure_self_in_barriers({:arrived, MapSet.new()})
end
Expand Down
3 changes: 2 additions & 1 deletion lib/elevator/hardware/outputs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ defmodule Elevator.Hardware.Outputs do
Driver.set_motor_direction(:stop)
end

@spec set_outputs(FSM.State.t(), Elevator.OrderUtils.combined_order_map()) :: any()
@spec set_outputs(FSM.State.t(), Elevator.OrderUtils.combined_order_map()) :: :ok
def set_outputs(state, light_orders) do
set_door_light(state)
set_motors(state)
set_floor_light(state)
set_order_lights(light_orders)
:ok
end

defp set_motors(elevator_state) do
Expand Down
8 changes: 4 additions & 4 deletions lib/elevator/order_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ defmodule Elevator.OrderUtils do
}

@spec orders_above?(combined_order_map(), Elevator.floor()) :: boolean()
def orders_above?(reqs, floor) do
Enum.any?(reqs, fn {f, _} -> f > floor end)
def orders_above?(orders, floor) do
Enum.any?(orders, fn {f, _} -> f > floor end)
end

@spec orders_below?(combined_order_map(), Elevator.floor()) :: boolean()
def orders_below?(reqs, floor) do
Enum.any?(reqs, fn {f, _} -> f < floor end)
def orders_below?(orders, floor) do
Enum.any?(orders, fn {f, _} -> f < floor end)
end

@spec combine_hall_and_cab(
Expand Down
Loading