get_next_destination #22

Merged
sebgab merged 26 commits from get_next_destination into main 2026-03-17 10:59:32 +00:00
Owner

Closes #13

Closes #13
add psudo code for the elevator_controller
All checks were successful
/ build_and_test (push) Successful in 23s
5392eddf0e
add includes for the elevator_controller
Some checks failed
/ build_and_test (push) Failing after 16s
84d26d319f
add system state to the elevator controller function
Some checks failed
/ build_and_test (push) Failing after 22s
eef35be564
Add logger and comments
Some checks failed
/ build_and_test (push) Failing after 24s
658db9f49d
add comment
Some checks failed
/ build_and_test (push) Failing after 20s
b77aa3ddd6
made ElevatorInterface pub
All checks were successful
/ build_and_test (push) Successful in 33s
61ae49bace
add fetch state, and set the elevator to stop
All checks were successful
/ build_and_test (push) Successful in 31s
100b324970
Hemmily self-assigned this 2026-02-18 17:57:18 +00:00
Add get_calls_as_ref function
Some checks failed
/ build_and_test (push) Failing after 22s
a1a701d1f9
Some get_next_destination progress
Some checks failed
/ build_and_test (push) Failing after 22s
11d68dd28c
Add .idea to gitignore
Some checks failed
/ build_and_test (push) Failing after 22s
0d8bbd90d4
Merge branch 'main' into get_next_destination
Some checks failed
/ build_and_test (push) Failing after 14s
/ Static Release Build (push) Has been skipped
101c4394cc
Implement get_next_destination (hopefully)
All checks were successful
/ build_and_test (push) Successful in 21s
/ Static Release Build (push) Has been skipped
a30006e3b6
Add tests
All checks were successful
/ build_and_test (push) Successful in 21s
/ Static Release Build (push) Has been skipped
5e35fbfa36
Hemmily changed title from WIP: get_next_destination to get_next_destination 2026-03-08 09:00:52 +00:00
Merge branch 'main' into get_next_destination
Some checks failed
/ build_and_test (push) Failing after 15s
/ Static Release Build (push) Has been skipped
bb84be0764
Remove extra closing bracket
Some checks failed
/ build_and_test (push) Failing after 16s
/ Static Release Build (push) Has been skipped
43bf593464
Add back a driver that disappeared in the merge
Some checks failed
/ build_and_test (push) Failing after 16s
/ Static Release Build (push) Has been skipped
6aec5a4374
Maybe fix it not compiling
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
1288d42ddb
Merge branch 'main' into get_next_destination
All checks were successful
/ build_and_test (push) Successful in 26s
/ Static Release Build (push) Has been skipped
26fca7bb2b
Athamantis requested changes 2026-03-08 10:19:40 +00:00
Dismissed
@ -207,0 +212,4 @@
/// Get a mutable reference to a call by index.
/// Only available in tests to allow setting call state without exposing internals.
#[cfg(test)]
Owner

unsure if this is allowed?
idk

unsure if this is allowed? idk
Hemmily marked this conversation as resolved
@ -392,0 +410,4 @@
/// Set the current floor for _this_ elevator.
/// Only available in tests to avoid exposing this as a general interface.
#[cfg(test)]
pub fn set_current_floor_for_test(&mut self, floor: Option<Destination>) {
Owner

still unshure about this

you can in tests just do
{
self.elevators
.get_mut(&self.id)
.expect("Failed to get own elevator")
.set_current_floor(floor);
}

still unshure about this you can in tests just do { self.elevators .get_mut(&self.id) .expect("Failed to get own elevator") .set_current_floor(floor); }
Hemmily marked this conversation as resolved
@ -392,0 +419,4 @@
/// Set the direction for _this_ elevator.
/// Only available in tests to avoid exposing this as a general interface.
#[cfg(test)]
Owner

same as over

same as over
Hemmily marked this conversation as resolved
@ -461,0 +509,4 @@
// Check for unassigned/new
for call in calls {
if call.get_call_state() != CallState::New {
Owner

i think you have filter functions for this
https://medium.com/@jannden/33-most-useful-rust-iterator-methods-b56eb608de76

but it works

i think you have filter functions for this https://medium.com/@jannden/33-most-useful-rust-iterator-methods-b56eb608de76 but it works
Author
Owner

I tried but it just gives more errors later in the code, so I'm gonna keep the for

I tried but it just gives more errors later in the code, so I'm gonna keep the for
Hemmily marked this conversation as resolved
Athamantis requested changes 2026-03-08 10:22:32 +00:00
Dismissed
@ -612,0 +650,4 @@
/// Looks through all calls with CallState New and returns the destination of the closest one in the correct direction
/// All calls are considered if the elevator is Idle
/// Returns None if there is no calls
pub fn get_next_destination(&self) -> Option<Destination> {
Owner

have you seen how the elevator is implemented in elevator controller?
i think i would take a look at it too

have you seen how the elevator is implemented in elevator controller? i think i would take a look at it too
Author
Owner

Implemented like this
destination: Option,

So it should be ok like this

Implemented like this destination: Option<Destination>, So it should be ok like this
Hemmily marked this conversation as resolved
sebgab requested review from sebgab 2026-03-08 10:49:48 +00:00
sebgab requested changes 2026-03-08 11:08:10 +00:00
Dismissed
sebgab left a comment
Owner

Some small stuff

Some small stuff
@ -612,0 +669,4 @@
// Filter by direction
// Elevator moving up, skip calls below current floor
// Elevator moving down, skip calls above current floor
if ((elevator_direction == Some(Direction::Up)) && (elevator_current_floor >= call_destination))
Owner

Please tidy this up by moving things out of the if statement, currently the comment is required for me to understand the code.

e.g.

let going_up = (..);
let call_below = (..);

let call_wrong_way = going_up && call_below;

if call_wrong_way {
    (...)
}
Please tidy this up by moving things out of the if statement, currently the comment is required for me to understand the code. e.g. ```Rust let going_up = (..); let call_below = (..); let call_wrong_way = going_up && call_below; if call_wrong_way { (...) } ```
Hemmily marked this conversation as resolved
@ -834,1 +911,4 @@
/// Create a SystemState with no calls
/// Used for get_next_destination tests
fn create_empty_system_state() -> (SystemState, SystemStateChannelHandles) {
Owner

If it is only used for tests then it should be marked with #[cfg(test)].

I do also believe that this function already exists elsewhere, but I am too lazy to confirm.

If it is only used for tests then it should be marked with `#[cfg(test)]`. I do also believe that this function already exists elsewhere, but I am too lazy to confirm.
Author
Owner

I only found create_stateful_system_state, but will mark as with #[cfg(test)]

I only found create_stateful_system_state, but will mark as with #[cfg(test)]
Hemmily marked this conversation as resolved
@ -612,0 +660,4 @@
// Check for unassigned/new
for call in calls {
if call.get_call_state() != CallState::New {
Owner

This will make it so if an elevator has taken a call, then dies for some reason, that call will not be serviced.

This will make it so if an elevator has taken a call, then dies for some reason, that call will not be serviced.
Author
Owner

Use clone_applicable_calls() function instead of the if

Use clone_applicable_calls() function instead of the if
Hemmily marked this conversation as resolved
@ -612,0 +676,4 @@
// Check distance
let distance = call_destination.abs_diff(elevator_current_floor);
new_calls.push((call.get_call_id(), distance, call.get_direction(), call.get_destination()));
Owner

Could you make a struct to represent this rather than en tuple?

The struct can be local to this function, but it would help with readability.

Could you make a struct to represent this rather than en tuple? The struct can be local to this function, but it would help with readability.
Author
Owner

This is now a struct

This is now a struct
Hemmily marked this conversation as resolved
@ -76,1 +76,4 @@
}
/// Function takes the floor as a Destination and returns a u8
pub fn floor_number(&self) -> u8 {
Owner

I am unsure if it is more proper to have this function or to implement Into<u8>.

I am unsure if it is more proper to have this function or to implement `Into<u8>`.
Author
Owner

Into is now implemented

Into is now implemented
Hemmily marked this conversation as resolved
@ -77,0 +77,4 @@
/// Function takes the floor as a Destination and returns a u8
pub fn floor_number(&self) -> u8 {
*self as u8 + 1
Owner

This is error prone and dependent on the order of the elements in the enum.

Assign values to the enum rather than using the default, inferred values.

enum MyEnum {
  bar = 1
  foo = 2
}
This is error prone and dependent on the order of the elements in the enum. Assign values to the enum rather than using the default, inferred values. ```Rust enum MyEnum { bar = 1 foo = 2 } ```
Author
Owner

It now matches directly

pub fn floor_number(&self) -> u8 {
match self {
Destination::Floor1 => 1,
Destination::Floor2 => 2,
Destination::Floor3 => 3,
Destination::Floor4 => 4,
}
}

It now matches directly pub fn floor_number(&self) -> u8 { match self { Destination::Floor1 => 1, Destination::Floor2 => 2, Destination::Floor3 => 3, Destination::Floor4 => 4, } }
Hemmily marked this conversation as resolved
Fix pull request comments
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
86fc5aec46
sebgab left a comment
Owner

Implement the use of this function in set_destination in the SystemState impl.

Implement the use of this function in `set_destination` in the SystemState impl.
@ -462,2 +474,4 @@
}
/// Get the [HashMap] with [ElevatorInfo] as a reference
pub fn get_elevator_hashmap_as_ref(&self) -> &HashMap<ElevatorId, ElevatorInfo> {
Owner

Unused function, remove.

Unused function, remove.
Author
Owner

Removed

Removed
Hemmily marked this conversation as resolved
sebgab requested changes 2026-03-08 13:19:09 +00:00
Dismissed
sebgab left a comment
Owner

.

.
Implement set_destination
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
2fefed8108
Merge branch 'main' into get_next_destination
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
a78592e04c
Add an info message
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
c496a90489
Maybe stop crashing from hall calls
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
f019952094
Remove extra info print
All checks were successful
/ build_and_test (push) Successful in 25s
/ Static Release Build (push) Has been skipped
31f519c68a
Merge branch 'main' into get_next_destination
All checks were successful
/ build_and_test (push) Successful in 30s
/ Static Release Build (push) Has been skipped
cb6c55cd9a
No longer crashes, should be good to go now
All checks were successful
/ build_and_test (push) Successful in 30s
/ Static Release Build (push) Has been skipped
70e26e16d0
Hemmily requested review from sebgab 2026-03-08 23:02:32 +00:00
Add feature flag
All checks were successful
/ build_and_test (push) Successful in 30s
/ Static Release Build (push) Has been skipped
2242cf637e
It looks right?
All checks were successful
/ build_and_test (push) Successful in 31s
/ Static Release Build (push) Has been skipped
2dd8d28683
sebgab requested changes 2026-03-17 09:49:54 +00:00
Dismissed
@ -155,3 +156,3 @@
// Busy wait until there is a call to service
let mut num_calls_to_service: usize =
/*let mut num_calls_to_service: usize =
Owner

Remove commented code

Remove commented code
Author
Owner

removed

removed
Hemmily marked this conversation as resolved
@ -186,0 +203,4 @@
state.elevators.close_door();
}
tokio::time::sleep(Duration::from_millis(100)).await;
Owner

Why do we sleep here?

Why do we sleep here?
Author
Owner

It worked better with the delay

image

It worked better with the delay ![image](/attachments/65ebe47a-bc41-4ed2-8c1c-ada5b55a0f51)
199 KiB
Hemmily marked this conversation as resolved
@ -297,1 +315,3 @@
tokio::select! {
let result = get_floor_destination(state.clone()).await;
assert_eq!(result, None);
Owner

Why do we do some computation, then assert it to be None? Could this not just be deleted?

Why do we do some computation, then assert it to be None? Could this not just be deleted?
Author
Owner

Probably can, it is an older test and the functionality of the function has changed a little bit after. Used to have more logic after

Probably can, it is an older test and the functionality of the function has changed a little bit after. Used to have more logic after
Hemmily marked this conversation as resolved
@ -298,0 +316,4 @@
let result = get_floor_destination(state.clone()).await;
assert_eq!(result, None);
/*tokio::select! {
Owner

Delete commented out code.

Delete commented out code.
Author
Owner

deleted

deleted
Hemmily marked this conversation as resolved
@ -28,3 +28,3 @@
/// testing the "real" recv data did not return consistently
async fn recv(sync_notification_rx: &mut mpsc::UnboundedReceiver<()>) {
loop {
sync_notification_rx.recv().await;
Owner

The .await method on recv() has previosuly been shown to be unpredictable.
What was the basis for changing back to it?

The `.await` method on `recv()` has previosuly been shown to be unpredictable. What was the basis for changing back to it?
Author
Owner

The loop was blocking other functions from running. I haven't tested with more elevators so I don't really know if this will still be unpredictable or if it will work fine. But it was changed because it didn't let the functions in elevator_controller run at all

The loop was blocking other functions from running. I haven't tested with more elevators so I don't really know if this will still be unpredictable or if it will work fine. But it was changed because it didn't let the functions in elevator_controller run at all
Owner

It should do that with the yield in the loop.

It should do that with the yield in the loop.
Owner

Closed due to the creation of #42

Closed due to the creation of #42
sebgab marked this conversation as resolved
@ -30,1 +30,3 @@
loop {
sync_notification_rx.recv().await;
/*loop {
Owner

Delete commented out code.

Delete commented out code.
Author
Owner

deleted

deleted
Hemmily marked this conversation as resolved
@ -673,0 +709,4 @@
/// Returns None if there is no calls
pub fn get_next_destination(&self) -> (Option<Destination>, Option<Direction>) {
/// One single applicable call, with necessary values to calculate next destination
struct ApplicableCalls {
Owner

Two things:

  1. Type name is in plural, but only represents singular datapoint.

  2. Why do we create this type rather than just using ElevatorCall?

Two things: 1. Type name is in plural, but only represents singular datapoint. 2. Why do we create this type rather than just using `ElevatorCall`?
Author
Owner

Mostly because not all the fields are needed. Seemed easier while writing it, but if it's an easy change it can be changed

Mostly because not all the fields are needed. Seemed easier while writing it, but if it's an easy change it can be changed
Author
Owner

For thing 1: It is now singularimage

For thing 1: It is now singular![image](/attachments/820985ec-f16c-4ff7-9ffa-c1d3ddf9fb64)
Author
Owner

For thing 2: I could probably have used ElevatorCall. However, I don't really want to change it now, so
image

For thing 2: I could probably have used ElevatorCall. However, I don't really want to change it now, so ![image](/attachments/41917f29-6142-4885-9888-f1a7c95fd163)
250 KiB
Hemmily marked this conversation as resolved
@ -671,2 +704,4 @@
}
/// Get the elevator's next [Destination]
/// Looks through all calls with CallState New and returns the destination of the closest one in th e correct direction
Owner

What's with the "in th e correct"?

What's with the "in th e correct"?
Author
Owner

looks like ive accidentally hit tab or something like that in the middle. Spaces removed now

looks like ive accidentally hit tab or something like that in the middle. Spaces removed now
Hemmily marked this conversation as resolved
@ -673,0 +707,4 @@
/// Looks through all calls with CallState New and returns the destination of the closest one in th e correct direction
/// All calls are considered if the elevator is Idle
/// Returns None if there is no calls
pub fn get_next_destination(&self) -> (Option<Destination>, Option<Direction>) {
Owner

Why do we use a tuple here instead of a struct?

Additionally, by the looks of it this function always returns either (Some, Some) or (None, None), as such a return type of Result<(Destination, Direction> seems more appropriate.

Why do we use a tuple here instead of a struct? Additionally, by the looks of it this function always returns either `(Some, Some)` or `(None, None)`, as such a return type of `Result<(Destination, Direction>` seems more appropriate.
Author
Owner

This is true, will change and see if it breaks other things

image

This is true, will change and see if it breaks other things ![image](/attachments/11913fbd-de95-4101-81b2-78a686d463a3)
303 KiB
Author
Owner

Update: it does break other things. Probably should have from the start though

image

Update: it does break other things. Probably should have from the start though ![image](/attachments/ce466158-53dc-463f-90e8-ebb9397f963a)
637 KiB
Hemmily marked this conversation as resolved
@ -237,2 +243,4 @@
/// The timestamp of the last update from this elevator
last_seen: ElevatorTime,
/// The ID of the current call of the elevator
current_call_id: Option<SmallUid>,
Owner

:o, I see this was added here as well, very nice!

:o, I see this was added here as well, very nice!
Author
Owner

image

![image](/attachments/dfcea1d5-2e35-4239-b5aa-995fc0c09fcf)
196 KiB
Hemmily marked this conversation as resolved
Merge branch 'main' into get_next_destination
All checks were successful
/ build_and_test (push) Successful in 31s
/ Static Release Build (push) Has been skipped
b75a5361a3
Athamantis requested changes 2026-03-17 09:52:43 +00:00
Dismissed
@ -141,2 +141,3 @@
/// Returns the [`Destination`]
async fn get_floor_destination(system_state: Arc<RwLock<SystemState>>) -> Destination {
async fn get_floor_destination(system_state: Arc<RwLock<SystemState>>) -> Option<Destination> {
debug!("get_floor_destination called");
Owner

trace?

trace?
Author
Owner

sure

sure
Hemmily marked this conversation as resolved
@ -155,3 +156,3 @@
// Busy wait until there is a call to service
let mut num_calls_to_service: usize =
/*let mut num_calls_to_service: usize =
Owner

either way, delete unused code

either way, delete unused code
Author
Owner

image

![image](/attachments/5c3ce609-dce2-4959-9e4d-ed7292d48841)
296 KiB
Hemmily marked this conversation as resolved
@ -196,4 +216,1 @@
)
.await;
debug!("Current floor is {:?}", current_floor);
Owner

move with current floor declaration

move with current floor declaration
Author
Owner

image

![image](/attachments/e47c6050-ae93-4199-a7ba-882406d32f5f)
Hemmily marked this conversation as resolved
@ -186,0 +197,4 @@
Some(destination) => destination,
None => {
// No calls - close doors before returning
debug!("No calls found, closing door");
Owner

why do we need to close the door? can it not be open?

why do we need to close the door? can it not be open?
Author
Owner

Having them stay open sometimes caused problems with deleting the call it just serviced. It's also kinda weird to have an elevator just stand there with open doors?

Having them stay open sometimes caused problems with deleting the call it just serviced. It's also kinda weird to have an elevator just stand there with open doors?
Owner

okay

okay
Athamantis marked this conversation as resolved
@ -186,0 +203,4 @@
state.elevators.close_door();
}
tokio::time::sleep(Duration::from_millis(100)).await;
Owner

why sleep?

why sleep?
Author
Owner

It worked better with (10/10 nap the problems away)

image

It worked better with (10/10 nap the problems away) ![image](/attachments/61fb0c21-1493-4659-a97a-4a02f4cbf012)
Hemmily marked this conversation as resolved
@ -186,0 +204,4 @@
}
tokio::time::sleep(Duration::from_millis(100)).await;
return;
Owner

add comment here to say that the whole function returns

add comment here to say that the whole function returns
Author
Owner

image

![image](/attachments/30c5dba7-25ea-4c5f-8271-d8b623372d58)
583 KiB
Hemmily marked this conversation as resolved
@ -259,6 +276,7 @@ async fn elevator_controller(system_state: Arc<RwLock<SystemState>>, elevator: E
/// Task for the elevator_controller
pub async fn elevator_controller_task(state: Arc<RwLock<SystemState>>, elevator: Elevator) -> ! {
loop {
debug!("elevator_controller_task loop iteration");
Owner

remove or move to trace

remove or move to trace
Author
Owner

Forgot to take it away before, it was just there to see if we ever went into the loop at one point (spoiler alert: we do now)

image

Forgot to take it away before, it was just there to see if we ever went into the loop at one point (spoiler alert: we do now) ![image](/attachments/c840753d-5f85-4340-a694-60242b4fc790)
1.3 MiB
Hemmily marked this conversation as resolved
@ -300,3 +322,3 @@
},
_ = tokio::time::sleep(std::time::Duration::from_millis(100)) => {}
}
}*/
Owner

remove unused code
and either fix the test, or remove the whole empty test

remove unused code and either fix the test, or remove the whole empty test
Author
Owner

Will remove, as this test is written before the functionality slightly changed and it is not fully accurate anymore

Will remove, as this test is written before the functionality slightly changed and it is not fully accurate anymore
Hemmily marked this conversation as resolved
@ -30,1 +30,3 @@
loop {
sync_notification_rx.recv().await;
/*loop {
Owner

why is this commented out?

why is this commented out?
Author
Owner

Because it was busy waiting and blocking other functions from running (hence all the extra debugs all over the place). This might be an issue just when on one laptop, but we will see quickly when we do with 3

Because it was busy waiting and blocking other functions from running (hence all the extra debugs all over the place). This might be an issue just when on one laptop, but we will see quickly when we do with 3
Hemmily marked this conversation as resolved
@ -673,0 +708,4 @@
/// All calls are considered if the elevator is Idle
/// Returns None if there is no calls
pub fn get_next_destination(&self) -> (Option<Destination>, Option<Direction>) {
/// One single applicable call, with necessary values to calculate next destination
Owner

move struct out?

move struct out?
Author
Owner

(In reality I should have used an existing one, however I think changing to using that is gonna take time). This struct was made here because I only use it here however

image

(In reality I should have used an existing one, however I think changing to using that is gonna take time). This struct was made here because I only use it here however ![image](/attachments/02fa04d1-f448-4d6b-97e5-b93868681e67)
Hemmily marked this conversation as resolved
Resolve comments
Some checks failed
/ build_and_test (push) Failing after 26s
/ Static Release Build (push) Has been skipped
1eb926d76b
sebgab approved these changes 2026-03-17 10:50:21 +00:00
Athamantis approved these changes 2026-03-17 10:50:43 +00:00
Dismissed
Athamantis left a comment
Owner

image, rotate:90

![image, rotate:90](/attachments/e4c9f289-d88a-47d9-8b4e-92d2a81a00fb)
171 KiB
Athamantis dismissed Athamantis's review 2026-03-17 10:56:48 +00:00
Reason:

not compiling

samle -> sample plus typos
All checks were successful
/ build_and_test (push) Successful in 31s
/ Static Release Build (push) Has been skipped
9e937fcae2
sebgab merged commit 1da96bcac9 into main 2026-03-17 10:59:32 +00:00
sebgab deleted branch get_next_destination 2026-03-17 10:59:33 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TTK4145/elevator!22
No description provided.