Loco

Struct Loco 

Source
pub struct Loco { /* private fields */ }
Expand description

Represents a DCC Locomotive that can be controlled via a Z21 station.

This struct provides methods to control various aspects of a model train locomotive, including speed, direction, functions (lights, sounds, etc.), and emergency stops. It communicates with the locomotive through a Z21 station using the XBus protocol.

Implementations§

Source§

impl Loco

Source

pub async fn control(station: Arc<Z21Station>, address: u16) -> Result<Loco>

Initializes control over a locomotive with the specified address.

This method establishes communication with a locomotive using its DCC address and subscribes to information about its state. It uses the default throttle steps configuration (128 steps).

§Arguments
  • station - Arc reference to a connected Z21Station
  • address - DCC address of the locomotive (1-9999)
§Returns

A new Loco instance if successful.

§Errors

Returns an io::Error if:

  • Communication with the Z21 station fails
  • The locomotive does not respond
§Example
let loco = Loco::control(station.clone(), 3).await?;
Examples found in repository?
examples/loco_control.rs (line 10)
6async fn main() -> std::io::Result<()> {
7    let station = Arc::new(Z21Station::new("192.168.0.111:21105").await?);
8
9    // Control a locomotive with address 3
10    let loco = Loco::control(station.clone(), 4).await?;
11
12    // Subscribe to locomotive state changes
13    loco.subscribe_loco_state(Box::new(|state| {
14        println!(
15            "Locomotive speed: {}%",
16            state.speed_percentage.unwrap_or(0.)
17        );
18    }));
19
20    // Turn on the headlights
21    loco.set_headlights(true).await?;
22
23    // Set speed to 50% forward
24    loco.drive(50.0).await?;
25
26    // Wait for 5 seconds
27    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
28
29    // Gradually stop
30    loco.stop().await?;
31
32    Ok(())
33}
Source

pub async fn control_with_steps( station: Arc<Z21Station>, address: u16, steps: DccThrottleSteps, ) -> Result<Loco>

Initializes control over a locomotive with specified address and DCC stepping.

Similar to control() but allows specifying the throttle stepping mode (14, 28, or 128 steps) for more precise control or compatibility with different locomotive decoders.

§Arguments
  • station - Arc reference to a connected Z21Station
  • address - DCC address of the locomotive (1-9999)
  • steps - DCC throttle steps configuration
§Returns

A new Loco instance if successful.

§Errors

Returns an io::Error if:

  • Communication with the Z21 station fails
  • The locomotive does not respond
§Example
let loco = Loco::control_with_steps(
    station.clone(),
    3,
    DccThrottleSteps::Steps28
).await?;
Source

pub async fn stop(&self) -> Result<()>

Performs a normal locomotive stop, equivalent to setting speed to 0.

This stop applies braking with a braking curve, providing a gradual and realistic deceleration.

§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Gradually stop the locomotive
loco.stop().await?;
Examples found in repository?
examples/loco_control.rs (line 30)
6async fn main() -> std::io::Result<()> {
7    let station = Arc::new(Z21Station::new("192.168.0.111:21105").await?);
8
9    // Control a locomotive with address 3
10    let loco = Loco::control(station.clone(), 4).await?;
11
12    // Subscribe to locomotive state changes
13    loco.subscribe_loco_state(Box::new(|state| {
14        println!(
15            "Locomotive speed: {}%",
16            state.speed_percentage.unwrap_or(0.)
17        );
18    }));
19
20    // Turn on the headlights
21    loco.set_headlights(true).await?;
22
23    // Set speed to 50% forward
24    loco.drive(50.0).await?;
25
26    // Wait for 5 seconds
27    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
28
29    // Gradually stop
30    loco.stop().await?;
31
32    Ok(())
33}
Source

pub async fn halt(&self) -> Result<()>

Stops the train immediately (emergency stop).

Unlike the normal stop() method, this immediately cuts power to the locomotive, causing an abrupt stop. This should be used only in emergency situations.

§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Emergency stop the locomotive
loco.halt().await?;
Source

pub async fn drive(&self, speed_percent: f64) -> Result<()>

Sets the speed of the locomotive in percent.

This method controls both the speed and direction of the locomotive:

  • Positive values move the locomotive forward
  • Negative values move the locomotive backward
  • Zero value gradually stops the locomotive using a braking curve

The speed is automatically scaled based on the configured DCC throttle steps.

§Arguments
  • speed_percent - Speed percentage (-100.0 to 100.0)
§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Drive forward at 50% speed
loco.drive(50.0).await?;

// Drive backward at 25% speed
loco.drive(-25.0).await?;

// Stop gradually
loco.drive(0.0).await?;
Examples found in repository?
examples/loco_control.rs (line 24)
6async fn main() -> std::io::Result<()> {
7    let station = Arc::new(Z21Station::new("192.168.0.111:21105").await?);
8
9    // Control a locomotive with address 3
10    let loco = Loco::control(station.clone(), 4).await?;
11
12    // Subscribe to locomotive state changes
13    loco.subscribe_loco_state(Box::new(|state| {
14        println!(
15            "Locomotive speed: {}%",
16            state.speed_percentage.unwrap_or(0.)
17        );
18    }));
19
20    // Turn on the headlights
21    loco.set_headlights(true).await?;
22
23    // Set speed to 50% forward
24    loco.drive(50.0).await?;
25
26    // Wait for 5 seconds
27    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
28
29    // Gradually stop
30    loco.stop().await?;
31
32    Ok(())
33}
Source

pub fn subscribe_loco_state( &self, subscriber: Box<dyn Fn(LocoState) + Send + Sync>, )

Subscribes to locomotive state changes.

This method sets up a background task that listens for locomotive state events from the Z21 station and calls the provided callback function whenever the state changes.

§Arguments
  • subscriber - Callback function that receives locomotive state updates
§Example
loco.subscribe_loco_state(Box::new(|state| {
    println!("Locomotive speed: {}, direction: {}",
             state.speed,
             if state.direction { "forward" } else { "backward" });
}));
Examples found in repository?
examples/loco_control.rs (lines 13-18)
6async fn main() -> std::io::Result<()> {
7    let station = Arc::new(Z21Station::new("192.168.0.111:21105").await?);
8
9    // Control a locomotive with address 3
10    let loco = Loco::control(station.clone(), 4).await?;
11
12    // Subscribe to locomotive state changes
13    loco.subscribe_loco_state(Box::new(|state| {
14        println!(
15            "Locomotive speed: {}%",
16            state.speed_percentage.unwrap_or(0.)
17        );
18    }));
19
20    // Turn on the headlights
21    loco.set_headlights(true).await?;
22
23    // Set speed to 50% forward
24    loco.drive(50.0).await?;
25
26    // Wait for 5 seconds
27    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
28
29    // Gradually stop
30    loco.stop().await?;
31
32    Ok(())
33}
Source

pub async fn set_function(&self, function_index: u8, action: u8) -> Result<()>

Controls a locomotive function (F0-F31).

This method allows controlling the various functions of a DCC locomotive, such as lights, sounds, couplers, smoke generators, and other features. The specific functions available depend on the locomotive decoder.

§Arguments
  • function_index - The function number (0-31) where 0 represents F0 (typically lights)
  • action - The action to perform:
    • 0: Turn function OFF
    • 1: Turn function ON
    • 2: Toggle function state
§Errors

Returns an io::Error if:

  • The function index is invalid (must be 0-31)
  • The action is invalid (must be 0-2)
  • The packet fails to send
  • The Z21 station does not respond
§Example
// Turn on the locomotive lights (F0)
loco.set_function(0, 1).await?;

// Toggle the horn (assuming it's on F2)
loco.set_function(2, 2).await?;
Source

pub async fn function_on(&self, function_index: u8) -> Result<()>

Turns on a specific locomotive function.

This is a convenience method that calls set_function() with the ON action.

§Arguments
  • function_index - The function number (0-31) where 0 represents F0 (typically lights)
§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Turn on the locomotive lights (F0)
loco.function_on(0).await?;

// Activate the horn (assuming it's on F2)
loco.function_on(2).await?;
Source

pub async fn function_off(&self, function_index: u8) -> Result<()>

Turns off a specific locomotive function.

This is a convenience method that calls set_function() with the OFF action.

§Arguments
  • function_index - The function number (0-31) where 0 represents F0 (typically lights)
§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Turn off the locomotive lights (F0)
loco.function_off(0).await?;

// Deactivate the horn (assuming it's on F2)
loco.function_off(2).await?;
Source

pub async fn function_toggle(&self, function_index: u8) -> Result<()>

Toggles a specific locomotive function (if on, turns off; if off, turns on).

This is a convenience method that calls set_function() with the TOGGLE action.

§Arguments
  • function_index - The function number (0-31) where 0 represents F0 (typically lights)
§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Toggle the locomotive lights (F0)
loco.function_toggle(0).await?;

// Toggle the horn (assuming it's on F2)
loco.function_toggle(2).await?;
Source

pub async fn set_headlights(&self, on: bool) -> Result<()>

Convenience method to control the locomotive’s headlights (F0).

This method simplifies controlling the locomotive’s headlights, which are typically mapped to function F0 in DCC decoders.

§Arguments
  • on - Whether to turn the lights on (true) or off (false)
§Errors

Returns an io::Error if the packet fails to send, or Z21 does not respond.

§Example
// Turn on the locomotive headlights
loco.set_headlights(true).await?;

// Turn off the locomotive headlights
loco.set_headlights(false).await?;
Examples found in repository?
examples/loco_control.rs (line 21)
6async fn main() -> std::io::Result<()> {
7    let station = Arc::new(Z21Station::new("192.168.0.111:21105").await?);
8
9    // Control a locomotive with address 3
10    let loco = Loco::control(station.clone(), 4).await?;
11
12    // Subscribe to locomotive state changes
13    loco.subscribe_loco_state(Box::new(|state| {
14        println!(
15            "Locomotive speed: {}%",
16            state.speed_percentage.unwrap_or(0.)
17        );
18    }));
19
20    // Turn on the headlights
21    loco.set_headlights(true).await?;
22
23    // Set speed to 50% forward
24    loco.drive(50.0).await?;
25
26    // Wait for 5 seconds
27    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
28
29    // Gradually stop
30    loco.stop().await?;
31
32    Ok(())
33}

Auto Trait Implementations§

§

impl Freeze for Loco

§

impl !RefUnwindSafe for Loco

§

impl Send for Loco

§

impl Sync for Loco

§

impl Unpin for Loco

§

impl !UnwindSafe for Loco

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.