# `brawl:device/onewire`

## Overview

The `brawl:device/onewire` interface defines a minimal, hardware-agnostic **1-Wire (Dallas/Maxim)** API for WebAssembly (WASM) modules. It provides a consistent way to control and monitor 1-wire devices across diverse embedded targets - ranging from microcontrollers to emulators - while remaining fully compatible with the WASM MVP specification.

Each function follows a simple convention: it returns a signed 32-bit integer, where negative values represent standardized error codes and non-negative values represent valid results or success indicators. This design keeps the ABI deterministic, low-overhead, and portable between environments, enabling WASM applications to interact directly with physical or virtual 1-wire devices without callbacks, threads, or host-specific extensions.

## Implementation Notes

This section outlines the expected behavior and conventions used by the `brawl:device/onewire` interface. It provides guidance for both host implementers and guest developers to ensure consistent behavior across WASM targets.

#### 1-Wire Bus Enumeration

`onewireCount()` returns the total number of 1-wire buses available on the target. `onewireList()` populates a memory buffer with a list of available 1-Wire bus identifiers (`uint8_t`) in the host environment’s canonical order.  Each 1-wire bus identifier can be passed directly to `onewireOpen()` to obtain a handle for further operations.

#### Interfacing With a 1-Wire Bus

Before reserving a pin, always call `onewireCapabilities()` to verify that it supports the desired modes. Use `onewireOpen()` to reserve the 1-wire bus and obtain a handle; this handle is passed to all subsequent operations. When the 1-wire bus is no longer needed, release it using `onewireClose()`. 1-Wire buses remain inactive and unpredictable until configured with `onewireSetSpeed()` to define their behavior and electrical characteristics.

#### Software 1-Wire (bit-banged on GPIO)

A 1-Wire bus may be emulated on a single GPIO pin using open-drain signalling and timing in software. The host reserves the selected pin and drives it low or releases it with a pull-up Strong-pullup after certain commands (e.g. DS18B20 Convert-T) may be emulated or unsupported depending on host capability. All normal 1-Wire commands are available on the resulting software bus handle.

To detect if the host supports a software implementation, call `onewireModuleCapabilities()` check for the `ONEWIRE_CAPS_SW_PORT` capability, a 1-Wire bus can then be created using the `onewireOpenOnPins()` function.

#### Error Codes

All `brawl:device/onewire` functions return a signed 32-bit integer (`int32_t`), which encodes both result and error information:

| Value      |                                                                          |
|------------|--------------------------------------------------------------------------|
| `ret < 0`  | an error occurred.                                                       |
| `ret == 0` | operation completed successfully (or no value to return).                |
| `ret > 0`  | operation succeeded and returned a value (e.g., a data value or handle). |

All memory access operations are bounds-checked by the host; going outside will return a `I2C_ERROR_MEMORY_OOB` error.

## Constants

#### ONEWIRE Errors

All functions return a signed 32-bit integer (`int32_t`).  If the value is **negative**, it represents an error code from the table below:

| Constant                       |                                                                            |
|--------------------------------|----------------------------------------------------------------------------|
| `ONEWIRE_ERROR_BUSY`           | The 1-Wire bus is already in use or reserved by another handle.            |
| `ONEWIRE_ERROR_UNSUPPORTED`    | The requested operation or capability is not supported on this 1-Wire bus. |
| `ONEWIRE_ERROR_TIMEOUT`        | The operation did not complete within the expected time.                   |
| `ONEWIRE_ERROR_INVALID_HANDLE` | The handle provided was invalid for the operation requested.               |
| `ONEWIRE_ERROR_INVALID_ARG`    | The argument provided was invalid for the operation requested.             |
| `ONEWIRE_ERROR_MEMORY_OOB`     | The requested operation would result in a MEMORY_OOB Error.                |
| `ONEWIRE_ERROR_NO_DEVICE`      | No device was found on the 1-Wire bus.                                     |
| `ONEWIRE_ERROR_CRC`            | The operation resulted in a CRC error.                                     |

A return value **`>= 0`** indicates success - either `0` for non-returning operations or a positive value for operations that produce a result.

#### GPIO Capabilities

Each 1-Wire bus can support one or more capabilities, reported by `onewireModuleCapabilities()` and `onewireCapabilities()`. These are bit-flags and may be combined using bitwise OR.

| Constant (Flag)              |                                                                     |
|------------------------------|---------------------------------------------------------------------|
| `ONEWIRE_CAPS_CONTROLLER`    | Supports master role.                                               |
| `ONEWIRE_CAPS_MULTIDROP`     | Supports multi-devices.                                             |
| `ONEWIRE_CAPS_OVERDRIVE`     | Supports 1-Wire overdrive speed.                                    |
| `ONEWIRE_CAPS_STRONG_PULLUP` | Host can source strong pullup.                                      |
| `ONEWIRE_CAPS_SEARCH_HW`     | Host can accelerate ROM search.                                     |
| `ONEWIRE_CAPS_SW_PORT`       | Supports creating a 1-Wire bus on an arbitrary GPIO pin.            |

Combine capability flags with the bitwise OR operator (`|`) to describe a pin that supports multiple features.

#### Speed Options

Possible speed settings.

| Constant                  |                  |
|---------------------------|------------------|
| `ONEWIRE_SPEED_STANDARD`  | Standard speed.  |
| `ONEWIRE_SPEED_OVERDRIVE` | Overdrive speed. |

#### Search Options

Possible search settings.

| Constant                    |                  |
|-----------------------------|------------------|
| `ONEWIRE_SEARCH_NORMAL`     | Normal search.   |
| `ONEWIRE_SEARCH_ALARM_ONLY` |  |

## Application Programming Interface (API)

```
//--------------------------------------------------------------------------
// brawl:device/onewire

// ONEWIRE errors
enum ONEWIRE_ERROR {
                         // >= 0              no error
  ONEWIRE_ERROR_BUSY         = -1,         // 1-Wire bus busy
  ONEWIRE_ERROR_UNSUPPORTED  = -2,         // 1-Wire bus operation unsupported
  ONEWIRE_ERROR_TIMEOUT      = -3,         // 1-Wire bus operation timed out
  ONEWIRE_ERROR_INVALID_ARG  = -4,         // invalid argument
  ONEWIRE_ERROR_MEMORY_OOB   = -5,         // memory OOB
  ONEWIRE_ERROR_NO_DEVICE    = -6,         // no presence pulse, or search found none
  ONEWIRE_ERROR_CRC          = -7          // optional: used by helper ops that verify CRC
};

// ONEWIRE capabilities (flags)
enum ONEWIRE_CAPS {
  ONEWIRE_CAPS_CONTROLLER    = (1u << 0),  // master role
  ONEWIRE_CAPS_MULTIDROP     = (1u << 1),  // multi-device bus
  ONEWIRE_CAPS_OVERDRIVE     = (1u << 2),  // support 1-Wire overdrive speed
  ONEWIRE_CAPS_STRONG_PULLUP = (1u << 3),  // host can source strong pullup
  ONEWIRE_CAPS_SEARCH_HW     = (1u << 4),  // host can accelerate ROM search
  ONEWIRE_CAPS_SW_PORT       = (1u << 5)   // supports creating a 1-Wire bus on an arbitrary GPIO pin
};

// ONEWIRE speed
enum ONEWIRE_SPEED {
  ONEWIRE_SPEED_STANDARD     = 0,
  ONEWIRE_SPEED_OVERDRIVE    = 1
};

// ONEWIRE search
enum ONEWIRE_SEARCH {
  ONEWIRE_SEARCH_NORMAL      = 0,
  ONEWIRE_SEARCH_ALARM_ONLY  = 1
};

int32_t // ONEWIRE_ERROR|ONEWIRE_CAPS
onewireModuleCapabilities(void);
```

#### Discovery

```
int32_t // ONEWIRE_ERROR|int32_t
onewireCount(void);

int32_t // ONEWIRE_ERROR|int32_t
onewireList(int32_t mem_ptr, int32_t max_items);

int32_t // ONEWIRE_ERROR|ONEWIRE_CAPS
onewireCapabilities(int32_t owBus);
```

#### Operation

```
int32_t // ONEWIRE_ERROR|int32_t
onewireOpen(int32_t owBus);

int32_t // ONEWIRE_ERROR|int32_t
onewireOpenOnPin(int32_t pinNum);

int32_t // ONEWIRE_ERROR|void
onewireSetSpeed(int32_t handle, enum ONEWIRE_SPEED speed);

int32_t // ONEWIRE_ERROR|void
onewireClose(int32_t handle);
```

#### Bus Primitives

```
int32_t // ONEWIRE_ERROR|void
onewireReset(int32_t handle);

int32_t // ONEWIRE_ERROR|void
onewireStrongPullup(int32_t handle, int32_t duration_us);

int32_t // ONEWIRE_ERROR|void
onewireSkipRom(int32_t handle);

int32_t // ONEWIRE_ERROR|int32_t
onewireMatchRom(int32_t handle, int32_t rom8_ptr);
```

#### Buffered I/O (linear memory)

```
int32_t // ONEWIRE_ERROR|int32_t
onewireRead(int32_t handle, int32_t rx_ptr, int32_t len, int32_t timeout_us);

int32_t // ONEWIRE_ERROR|int32_t
onewireWrite(int32_t handle, int32_t tx_ptr, int32_t len, int32_t strong_pullup_us);
```

#### 1-Wire Bus Device Search

```
int32_t // ONEWIRE_ERROR|int32_t
onewireSearch(int32_t handle, int32_t dst_ptr, int32_t max_roms, enum ONEWIRE_SEARCH opts);
```

## Example - DS18B20 (single-drop) (C)

```
#include <stdint.h>
#include <stdio.h>

#include "brawl-device-onewire.h"

static void onewire_err(int32_t rc, const char *what) {
    if (rc < 0) fprintf(stderr, "%s failed: %d\n", what, rc);
}

#define MAX_ONEWIRE 4

int main(void) {

    int32_t n, rc;
    uint8_t ids[MAX_ONEWIRE];
    int32_t ow_h;
    uint8_t cmd, scratch[9];
    int16_t raw;

    // enumerate 1-Wire buses (WASM MVP: caller-allocated buffer)
    n = onewireCount();
    if (n < 0) { onewire_err(n, "onewireCount"); return 1; }
    if (n > MAX_ONEWIRE) n = MAX_ONEWIRE;

    rc = onewireList((int32_t)(uintptr_t)ids, n);
    if (rc < 0) { onewire_err(rc, "onewireList"); return 1; }

    // did we find an 1-Wire bus?
    if (rc >= 0) {

        // pick first bust
        ow_h = onewireOpen(ids[0]);
        if (ow_h < 0) { onewire_err(led_h, "onewireOpen"); return 1; }

        // set he speed and reset to check presence
        rc = onewireSetSpeed(ow_h, ONEWIRE_SPEED_STANDARD);
        if (rc < 0) { onewire_err(rc, "onewireSetSpeed"); onewireClose(ow_h); return 1; }
        rc = onewireReset(ow_h);
        if (rc < 0) { onewire_err(rc, "onewireReset"); onewireClose(ow_h); return 1; }

        // start temperature conversion (0x44) with strong pullup (e.g. 750ms)
        cmd = 0x44;
        rc = onewireWrite(ow_h, (int32_t)(uintptr_t)&cmd, 1, 750000);
        if (rc < 0) { onewire_err(rc, "onewireWrite"); onewireClose(ow_h); return 1; }

        // read scratchpad: reset + skip + (0xBE, read 9 bytes)
        rc = onewireReset(ow_h);
        if (rc < 0) { onewire_err(rc, "onewireWrite"); onewireClose(ow_h); return 1; }
        rc = onewireSkipRom(ow_h);
        if (rc < 0) { onewire_err(rc, "onewireSkipRom"); onewireClose(ow_h); return 1; }
        cmd = 0xBE;
        rc = onewireWrite(ow_h, (int32_t)(uintptr_t)&cmd, 1, 0);
        if (rc < 0) { onewire_err(rc, "onewireWrite"); onewireClose(ow_h); return 1; }
        rc = onewireRead(ow_h, (int32_t)(uintptr_t)scratch, 9, 100000);
        if (rc < 0) { onewire_err(rc, "onewireRead"); onewireClose(ow_h); return 1; }

        // we should have received 9 bytes
        if (rc == 9) {

            // temperature in little-endian 16-bit
            raw  = (int16_t)((scratch[1] << 8) | scratch[0]);

            // TODO convert per sensor resolution
        }

        // close access to the 1-Wire bus
        rc = onewireClose(ow_h);
        if (rc < 0) onewire_err(rc, "onewireClose");
    }

    return 0;
}
```

#### Revision

2025-10 (draft)
