max30101-rs 0.1.0

Pure Rust driver for the MAX30101 PPG sensor.
Documentation
# max30101-rs

[![crates.io](https://img.shields.io/crates/v/max30101-rs.svg)](https://crates.io/crates/max30101-rs)
[![docs.rs](https://docs.rs/max30101-rs/badge.svg)](https://docs.rs/max30101-rs)
[![CI](https://github.com/JeromeHen/max30101-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/JeromeHen/max30101-rs/actions)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20%7C%20Apache--2.0-blue.svg)](./LICENSE)

## MAX30101 Rust Driver

Pure-Rust, `no_std` (with `alloc`) driver for the MAX30101 PPG (photoplethysmography) sensor.

This crate is a low-level, register-oriented implementation derived from the MAX30101 datasheet. It exposes a compact, register-centric API and a small transport abstraction so you can plug in your preferred I2C implementation.

This Rust crate is licensed under MIT OR Apache-2.0.

## Design Goals
- `no_std` compatible (with `alloc`)
- Support both synchronous (`blocking`) and asynchronous (`async`) I2C usage
- Small, register-oriented API close to the datasheet
- Transport-agnostic: users provide the concrete I2C implementation

## Crate Features

- `async` — enable asynchronous transport support using `embedded-hal-async` and `async-trait`.
- `blocking` — enable blocking transport support using `embedded-hal` traits.
- `shared-bus` — enable support for sharing a single bus instance between drivers (uses `embassy-sync` mutex types).

## Quick Overview

### High-Level Device Object

The crate exposes `Max30101<T>`, where `T` is a transport implementation. The `reg` module exposes register addresses, bitflags and small newtypes (enums and wrappers) for convenient and type-safe register manipulation.

Commonly-used items:

- `max30101_rs::Max30101` — main driver type.
- `max30101_rs::transport::I2cTransport` — provided I2C transport adapter.
- `max30101_rs::reg::MAX30101_I2C_ADDR` — default 7-bit I2C address.

## API highlights

Below are some functions, types and registers you will likely use when integrating this driver:

- Driver construction
    - `Max30101::new(transport)` — create the device instance.
    - `Max30101::destroy(self)` — consume the driver and return the underlying transport.

- Register access helpers
    - `read_reg` / `write_reg` — low-level register read/write helpers (async or blocking depending on feature).

- Interrupts
    - `interrupts_st_get()` — read current interrupt status registers.
    - `interrupts_en_set()` / `interrupts_en_get()` — enable/inspect enabled interrupt sources.
    - Registers: `MAX30101_INTERRUPT_STATUS_1`, `MAX30101_INTERRUPT_STATUS_2`, `MAX30101_INTERRUPT_ENABLE_1`, `MAX30101_INTERRUPT_ENABLE_2`.

- FIFO / samples
    - `fifo_config_set()` / `fifo_config_get()` — configure FIFO almost-full threshold, rollover and averaging.
    - `MAX30101_FIFO_DATA` — FIFO sample read register.

- Mode & reset
    - `mode_set()` / `mode_get()` — switch chip mode (`Mode` enum: `HeartRate`, `SpO2`, `MultiLED`).
    - `reset_set(true)` / `reset_get()` — trigger and query chip reset.
    - `shutdown_set()` / `shutdown_get()` — enter/exit shutdown mode.
    - Registers: `MAX30101_MODE_CONFIG`, `MAX30101_PART_ID`, `MAX30101_REV_ID`.

- LED configuration
    - `led_pw_set()` / `led_pw_get()` — set ADC resolution / LED pulse width (`LEDPW`).
    - `ledx_pa_set()` / `ledx_pa_get()` and `led1_pa_set()` .. `led4_pa_set()` — set per-LED pulse amplitude (LED current).
    - Registers: `MAX30101_LED1_PA` .. `MAX30101_LED4_PA`, `MAX30101_SPO2_CONFIG`.

- Sample rate & ADC range
    - `sample_rate_set()` / `sample_rate_get()` — configure sample rate (`SampleRate` enum).
    - `adc_range_set()` / `adc_range_get()` — configure ADC dynamic range (`ADCRange`).

- Transport helpers
    - `transport::I2cTransport::new(bus, address)` — adapter the crate provides to wrap an I2C bus and device address.

See the `reg` module for bitflags and small enums (e.g. `Mode`, `LEDPW`, `SampleRate`, `SmpAve`, `ADCRange`) to work with register fields in a type-safe way.

### Transport Abstraction

`Max30101<T>` is generic over a `Transport` implementation exposed in `transport`. Depending on enabled features the expected bus type differs:

- Without `shared-bus`: pass your concrete I2C implementation directly (e.g. an `embedded-hal` type).
- With `shared-bus`: pass a shared/mutex-wrapped bus (the crate expects `embassy-sync` mutex types when `shared-bus` is enabled).

The crate provides `I2cTransport::new(bus, address)` to construct a transport wrapper; the `bus` argument type depends on active features as described above.

## Examples

Below are minimal examples showing how to construct the driver for the async feature. Replace the `...` with your platform's concrete I2C type.

The blocking example is similar, just replace the `async`/`await` keywords and use blocking I2C types.

```rust
use max30101_rs::{Max30101, transport::I2cTransport, reg::MAX30101_I2C_ADDR};

// `I2C` should implement the embedded-hal-async I2C traits
let i2c = /* your embedded-hal I2C instance */;
let transport = I2cTransport::new(i2c, MAX30101_I2C_ADDR);
let mut dev = Max30101::new(transport);

// Reset the device, and wait for it to be ready
loop {
    if device.reset_set(true).await.is_ok() {
        break;
    }

    // Wait some time before retrying
}

// Make sure the device is not in shutdown mode
device.shutdown_set(false).await.unwrap();
// Wait some time for the device to be ready after exiting shutdown mode

// Test reading some device information
let part_id = device.part_id_get().await.unwrap();
let rev_id = device.rev_id_get().await.unwrap();

// Perform the rest of the setup here

// Use the device as specified in the datasheet
```

## Contributing

Contributions are welcome — PRs that add missing register APIs, improve examples, or enhance documentation are especially appreciated.

## License

The crate is dual-licensed under MIT or Apache-2.0 — see `LICENSE` for details.

## Contact / Author

Author: Jérôme Hendrick <jerome.hendrick@gmail.com>

Thanks for checking out this driver!