Metadata-Version: 2.4
Name: bcmio
Version: 1.1.2
Summary: Low-level GPIO library for Raspberry Pi 4 (BCM2711) using /dev/mem + mmap
Author: bcmio contributors
License: MIT
Keywords: raspberrypi,gpio,bcm2711,mmap,embedded,linux
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: System :: Hardware
Classifier: Topic :: Software Development :: Embedded Systems
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"

# bcmio

Biblioteca Python **low-level** para controle de GPIO do **Raspberry Pi 4 Model B (BCM2711)** usando
**acesso direto a registradores via `mmap`** e **`/dev/mem`** (MMIO).

> Aviso: acessar `/dev/mem` normalmente requer **root** (`sudo`). Use com cuidado: MMIO incorreto pode
> travar o sistema.

## Objetivos

- Performance: escrita/leitura direto em registradores (`GPSET/GPCLR/GPLEV`)
- Arquitetura modular: separar low-level (MMIO/registradores) e high-level (abstrações)
- API familiar (inspirada em RPi.GPIO/pigpio/gpiozero), mas **sem dependências** dessas bibliotecas
- Código tipado, com docstrings, pronto para evoluir para PWM/SPI/I2C/UART/interrupts/DMA

## Arquitetura (módulos)

- `bcmio/memory.py`: abertura de `/dev/mem`, `mmap`, leitura/escrita 32-bit
- `bcmio/constants.py`: offsets e constantes (GPIO modes, pulls, endereços base)
- `bcmio/gpio.py`: acesso aos registradores GPIO (FSEL, SET/CLR, LEV, PULL)
- `bcmio/pin.py`: classe `Pin` (alto nível) para um pino individual
- `bcmio/exceptions.py`: exceções customizadas
- `bcmio/utils.py`: helpers (validação, bit operations)
- `bcmio/pwm.py`, `bcmio/interrupts.py`: placeholders para evolução

## Como `mmap` funciona (visão geral)

1. Abrimos `/dev/mem` (arquivo especial que expõe memória física do SoC).
2. Fazemos `mmap` de uma página (ou mais) a partir do **endereço físico** dos periféricos GPIO.
3. A partir do ponteiro mapeado, fazemos leituras/escritas de 32 bits em offsets específicos.

No Linux, isso é MMIO (Memory Mapped I/O): escrever em um registrador mapeado altera o hardware.

## Endereços base (BCM2711)

O datasheet usa endereços no **barramento** (bus) como `0x7E200000` para o bloco GPIO. No Raspberry Pi 4,
o endereço **físico** tipicamente é `0xFE200000` (peripheral base `0xFE000000` + GPIO offset `0x200000`).

Esta biblioteca:

- expõe ambos em `bcmio.constants` (`GPIO_BASE_BUS`, `GPIO_BASE_PHYS_DEFAULT`)
- por padrão usa o **físico** (`0xFE200000`)
- permite sobrescrever o endereço base via `GPIO.open(base_phys=...)`

## Registradores GPIO usados (BCM2711)

Offsets relativos ao base do GPIO (bloco `GPIO`):

- `GPFSEL0..5` (Function Select): 3 bits por pino para definir `IN`, `OUT`, ou função alternativa
- `GPSET0..1` (Set): escrever `1` no bit seta o pino em nível alto (atômico)
- `GPCLR0..1` (Clear): escrever `1` no bit seta o pino em nível baixo (atômico)
- `GPLEV0..1` (Level): lê o nível atual do pino
- `GPIO_PUP_PDN_CNTRL_REG0..3`: 2 bits por pino para pull-up/pull-down/no-pull (BCM2711)

## Uso

### API estilo “módulo” (`GPIO`)

```python
from bcmio import GPIO

GPIO.safe_shutdown_enable()        # opcional: cleanup automático em SIGINT/SIGTERM/exit
GPIO.open()                       # inicializa /dev/mem + mmap
GPIO.setup(17, GPIO.OUT, pull=GPIO.PULL_NONE)
GPIO.write(17, GPIO.HIGH)
value = GPIO.read(17)
GPIO.cleanup()
```

### Context manager (shutdown seguro)

```python
from bcmio import GPIO

GPIO.safe_shutdown_enable()

with GPIO() as gpio:
    gpio.setup(17, gpio.OUT)
    gpio.write(17, gpio.HIGH)
```

### API orientada a objeto (`Pin`)

```python
from bcmio import Pin

led = Pin(17, mode=Pin.OUT)
led.high()
led.low()
led.toggle()
led.close()
```

## Exemplos

Veja `exemplos/`:

- `exemplos/blink.py`
- `exemplos/blink_safe.py`
- `exemplos/button_read.py`
- `exemplos/button_safe.py`
- `exemplos/toggle.py`
- `exemplos/read_digital.py`

Também há uma pasta `examples/` (API high-level e eventos):

- `examples/blink.py`
- `examples/button.py`
- `examples/pwm_led.py`
- `examples/interrupt_button.py`
- `examples/servo_control.py`
- `examples/safe_shutdown.py`

## Testes

Os testes em `testes/` não acessam `/dev/mem`. Eles usam um backend fake de memória para validar:

- cálculo de offsets e bitfields de `GPFSEL`
- `GPSET/GPCLR` e leitura em `GPLEV`
- configuração de pull em `GPIO_PUP_PDN_CNTRL_REGx`

Rodar:

```bash
python -m pip install -e ".[dev]"
pytest -q
```

## Segurança e boas práticas

- Use `sudo` apenas quando necessário.
- Prefira isolar e revisar o endereço base antes de usar em produção.
- Em produção, considere um modo “safe” ou `/dev/gpiomem` (não implementado aqui por requisito).
 - Se estiver usando PWM/eventos, evite apertar Ctrl+C repetidamente; `GPIO.safe_shutdown_enable()` já executa `cleanup()`.

### Safety limit (GPIO 0–27)

Por padrão, `bcmio` bloqueia pinos acima de **GPIO27** para reduzir riscos em hardware real. Se você
precisar acessar GPIOs além disso, ajuste a validação no seu código (API para override planejada).

### Backends

- `GPIO.set_backend("mmio")`: usa `/dev/mem` + `mmap` (default)
- `GPIO.set_backend("mock")`: registradores em memória (testes/CI)

### Eventos por hardware (edge detect)

Para um sistema event-driven sem polling de `GPLEV`, use:

```python
from bcmio import GPIO

GPIO.safe_shutdown_enable()
GPIO.open()
GPIO.setup(27, GPIO.IN, pull=GPIO.PULL_UP)

def cb(pin: int) -> None:
    print("edge event on", pin)

GPIO.add_event_detect(27, GPIO.FALLING, cb)  # GPEDS/GPFEN/GPREN
```
