pub struct CharacteristicReader { /* private fields */ }
Available on crate feature bluetoothd only.
Expand description

Streams data from a characteristic with low overhead.

Implementations

Maximum transmission unit.

Examples found in repository?
examples/gatt_client.rs (line 121)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
async fn exercise_characteristic(char: &Characteristic) -> Result<()> {
    println!("    Characteristic flags: {:?}", char.flags().await?);
    sleep(Duration::from_secs(1)).await;

    if char.flags().await?.read {
        println!("    Reading characteristic value");
        let value = char.read().await?;
        println!("    Read value: {:x?}", &value);
        sleep(Duration::from_secs(1)).await;
    }

    let data = vec![0xee, 0x11, 0x11, 0x0];
    println!("    Writing characteristic value {:x?} using function call", &data);
    char.write(&data).await?;
    sleep(Duration::from_secs(1)).await;

    if char.flags().await?.read {
        let value = char.read().await?;
        println!("    Read value back: {:x?}", &value);
        sleep(Duration::from_secs(1)).await;
    }

    println!("    Obtaining write IO");
    let mut write_io = char.write_io().await?;
    println!("    Write IO obtained");
    println!("    Writing characteristic value {:x?} five times using IO", &data);
    for _ in 0..5u8 {
        let written = write_io.write(&data).await?;
        println!("    {} bytes written", written);
    }
    println!("    Closing write IO");
    drop(write_io);
    sleep(Duration::from_secs(1)).await;

    println!("    Starting notification session");
    {
        let notify = char.notify().await?;
        pin_mut!(notify);
        for _ in 0..5u8 {
            match notify.next().await {
                Some(value) => {
                    println!("    Notification value: {:x?}", &value);
                }
                None => {
                    println!("    Notification session was terminated");
                }
            }
        }
        println!("    Stopping notification session");
    }
    sleep(Duration::from_secs(1)).await;

    println!("    Obtaining notification IO");
    let mut notify_io = char.notify_io().await?;
    println!("    Obtained notification IO with MTU={}", notify_io.mtu());
    for _ in 0..5u8 {
        let mut buf = vec![0; notify_io.mtu()];
        match notify_io.read(&mut buf).await {
            Ok(0) => {
                println!("    Notification IO end of stream");
                break;
            }
            Ok(read) => {
                println!("    Notified with {} bytes: {:x?}", read, &buf[0..read]);
            }
            Err(err) => {
                println!("    Notification IO failed: {}", &err);
                break;
            }
        }
    }
    println!("    Stopping notification IO");
    drop(notify_io);
    sleep(Duration::from_secs(1)).await;

    Ok(())
}
More examples
Hide additional examples
examples/gatt_echo_client.rs (line 68)
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
async fn exercise_characteristic(char: &Characteristic) -> Result<()> {
    let mut write_io = char.write_io().await?;
    println!("    Obtained write IO with MTU {} bytes", write_io.mtu());
    let mut notify_io = char.notify_io().await?;
    println!("    Obtained notification IO with MTU {} bytes", notify_io.mtu());

    // Flush notify buffer.
    let mut buf = [0; 1024];
    while let Ok(Ok(_)) = timeout(Duration::from_secs(1), notify_io.read(&mut buf)).await {}

    let mut rng = rand::thread_rng();
    for i in 0..1024 {
        let mut len = rng.gen_range(0..20000);

        // Try to trigger packet reordering over EATT.
        if i % 10 == 0 {
            // Big packet is split into multiple small packets.
            // (by L2CAP layer, because GATT MTU is bigger than L2CAP MTU)
            len = write_io.mtu(); // 512
        }
        if i % 10 == 1 {
            // Small packet can use different L2CAP channel when EATT is enabled.
            len = 20;
        }
        // Thus small packet can arrive before big packet.
        // The solution is to disable EATT in /etc/bluetooth/main.conf.

        println!("    Test iteration {} with data size {}", i, len);
        let data: Vec<u8> = (0..len).map(|_| rng.gen()).collect();

        // We must read back the data while sending, otherwise the connection
        // buffer will overrun and we will lose data.
        let read_task = tokio::spawn(async move {
            let mut echo_buf = vec![0u8; len];
            let res = match notify_io.read_exact(&mut echo_buf).await {
                Ok(_) => Ok(echo_buf),
                Err(err) => Err(err),
            };
            (notify_io, res)
        });

        // Note that write_all will automatically split the buffer into
        // multiple writes of MTU size.
        write_io.write_all(&data).await.expect("write failed");

        println!("    Waiting for echo");
        let (notify_io_back, res) = read_task.await.unwrap();
        notify_io = notify_io_back;
        let echo_buf = res.expect("read failed");

        if echo_buf != data {
            println!();
            println!("Echo data mismatch!");
            println!("Send data:     {:x?}", &data);
            println!("Received data: {:x?}", &echo_buf);
            println!();
            println!("By 512 blocks:");
            for (sent, recv) in data.chunks(512).zip(echo_buf.chunks(512)) {
                println!();
                println!(
                    "Send: {:x?} ... {:x?}",
                    &sent[0..4.min(sent.len())],
                    &sent[sent.len().saturating_sub(4)..]
                );
                println!(
                    "Recv: {:x?} ... {:x?}",
                    &recv[0..4.min(recv.len())],
                    &recv[recv.len().saturating_sub(4)..]
                );
            }
            println!();

            panic!("echoed data does not match sent data");
        }
        println!("    Data matches");
    }

    println!("    Test okay");
    Ok(())
}

Wait for a new characteristic value to become available.

Try to receive the characteristic value from a single notify or write operation.

Does not wait for new data to arrive.

Receive the characteristic value from a single notify or write operation.

Waits for data to arrive.

Consumes this object, returning the raw underlying file descriptor.

Trait Implementations

Extracts the raw file descriptor. Read more

Attempts to read from the characteristic value stream into buf.

When a buffer of size less than mtu bytes is provided, the received characteristic value will be buffered internally and split over multiple read operations. Thus, for best efficiency, provide a buffer of at least mtu bytes.

Formats the value using the given formatter. Read more
Consumes this object, returning the raw underlying file descriptor. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Creates a new AsyncRead instance that chains this stream with next. Read more
Pulls some bytes from this source into the specified buffer, returning how many bytes were read. Read more
Pulls some bytes from this source into the specified buffer, advancing the buffer’s internal cursor. Read more
Reads the exact number of bytes required to fill buf. Read more
Reads an unsigned 8 bit integer from the underlying reader. Read more
Reads a signed 8 bit integer from the underlying reader. Read more
Reads an unsigned 16-bit integer in big-endian order from the underlying reader. Read more
Reads a signed 16-bit integer in big-endian order from the underlying reader. Read more
Reads an unsigned 32-bit integer in big-endian order from the underlying reader. Read more
Reads a signed 32-bit integer in big-endian order from the underlying reader. Read more
Reads an unsigned 64-bit integer in big-endian order from the underlying reader. Read more
Reads an signed 64-bit integer in big-endian order from the underlying reader. Read more
Reads an unsigned 128-bit integer in big-endian order from the underlying reader. Read more
Reads an signed 128-bit integer in big-endian order from the underlying reader. Read more
Reads an 32-bit floating point type in big-endian order from the underlying reader. Read more
Reads an 64-bit floating point type in big-endian order from the underlying reader. Read more
Reads an unsigned 16-bit integer in little-endian order from the underlying reader. Read more
Reads a signed 16-bit integer in little-endian order from the underlying reader. Read more
Reads an unsigned 32-bit integer in little-endian order from the underlying reader. Read more
Reads a signed 32-bit integer in little-endian order from the underlying reader. Read more
Reads an unsigned 64-bit integer in little-endian order from the underlying reader. Read more
Reads an signed 64-bit integer in little-endian order from the underlying reader. Read more
Reads an unsigned 128-bit integer in little-endian order from the underlying reader. Read more
Reads an signed 128-bit integer in little-endian order from the underlying reader. Read more
Reads an 32-bit floating point type in little-endian order from the underlying reader. Read more
Reads an 64-bit floating point type in little-endian order from the underlying reader. Read more
Reads all bytes until EOF in this source, placing them into buf. Read more
Reads all bytes until EOF in this source, appending them to buf. Read more
Creates an adaptor which reads at most limit bytes from it. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.