> For the complete documentation index, see [llms.txt](https://erdilrf.gitbook.io/erdilrf-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://erdilrf.gitbook.io/erdilrf-docs/run-a-generated-byte-parser-check.md).

# Run a generated-byte parser check

This exercise feeds a finite byte buffer into the unchanged ErdiLRF 0.1.1 parser. It runs on a computer with a C++11 compiler, such as Clang or GCC, without a sensor or board.

The input `5C 02 11 EC` contains the little-endian raw count `0x1102 = 4354`. The family B checksum is the 8-bit inverse of the payload sum: `~(0x02 + 0x11) & 0xFF = 0xEC`.

## Prepare the directory

Download and extract the [official 0.1.1 archive](https://downloads.arduino.cc/libraries/github.com/yu911517778-a11y/ErdiLRF-0.1.1.zip) from the source page. Preserve its `LICENSE`. In a working directory, arrange these paths:

```
ErdiLRF-0.1.1/src/ErdiLRF.h
ErdiLRF-0.1.1/src/ErdiLRF.cpp
ErdiLRF-0.1.1/LICENSE
host/shim/Arduino.h
host/shim/Stream.h
host/native-synthetic-check.cpp
SyntheticUARTChecks/SyntheticFrame.h
```

Create the four exercise files below. Their code is MIT licensed; the full notice is on the next page and must remain with redistributed copies.

### `host/shim/Arduino.h`

```cpp
#ifndef ERDI_HOST_ARDUINO_H
#define ERDI_HOST_ARDUINO_H
#include <stddef.h>
#include <stdint.h>
unsigned long millis();
#endif
```

### `host/shim/Stream.h`

```cpp
#ifndef ERDI_HOST_STREAM_H
#define ERDI_HOST_STREAM_H
#include <stddef.h>
#include <stdint.h>
class Print {
 public:
  virtual ~Print() {}
  virtual size_t write(uint8_t) = 0;
  size_t write(const uint8_t *data, size_t size) {
    size_t result = 0;
    while (size--) result += write(*data++);
    return result;
  }
};
class Stream : public Print {
 public:
  virtual int available() = 0;
  virtual int read() = 0;
  virtual int peek() = 0;
  virtual void flush() = 0;
};
#endif
```

### `SyntheticUARTChecks/SyntheticFrame.h`

```cpp
#ifndef ERDI_SYNTHETIC_FRAME_H
#define ERDI_SYNTHETIC_FRAME_H

#include <ErdiLRF.h>

// MIT. Synthetic test helper; no module UART is opened.
class SyntheticStream : public Stream {
 public:
  SyntheticStream(const uint8_t *data, size_t size)
      : data_(data), size_(size), position_(0) {}

  int available() override { return (int)(size_ - position_); }
  int read() override {
    return position_ < size_ ? data_[position_++] : -1;
  }
  int peek() override {
    return position_ < size_ ? data_[position_] : -1;
  }
  void flush() override {}
  size_t write(uint8_t) override { return 1; }

 private:
  const uint8_t *data_;
  size_t size_;
  size_t position_;
};

inline ErdiStatus decodeSynthetic(ErdiModel model, const uint8_t frame[4],
                                ErdiMeasurement *measurement) {
  SyntheticStream stream(frame, 4);
  ErdiLRF driver(stream, model);
  driver.setTimeout(10);
  return driver.measure(measurement);
}

#endif
```

### `host/native-synthetic-check.cpp`

```cpp
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include "SyntheticFrame.h"

unsigned long millis() {
  static unsigned long ticks = 0;
  return ticks++;
}

int main() {
  uint8_t frame[4] = {0x5C, 0x02, 0x11, 0};
  frame[3] = erdiCheckSumB(&frame[1], 2);
  assert(frame[3] == 0xEC);
  ErdiMeasurement result;
  ErdiStatus status = decodeSynthetic(ERDI_LRF50H, frame, &result);
  assert(status == ERDI_OK && result.valid && !result.outOfRange);
  assert(result.raw == 4354 && fabs(result.metres - 43.54f) < 0.0001);
  printf("SYNTHETIC LRF50H status=%d raw=%u metres=%.3f\n",
         (int)status, (unsigned)result.raw, result.metres);
  status = decodeSynthetic(ERDI_LRF50VB, frame, &result);
  assert(status == ERDI_OK && result.valid && !result.outOfRange);
  assert(result.raw == 4354 && fabs(result.metres - 4.354f) < 0.0001);
  printf("SYNTHETIC LRF50VB status=%d raw=%u metres=%.3f\n",
         (int)status, (unsigned)result.raw, result.metres);
  frame[3] ^= 0x01;
  status = decodeSynthetic(ERDI_LRF50H, frame, &result);
  assert(status == ERDI_ERR_TIMEOUT && !result.valid);
  printf("SYNTHETIC CORRUPT status=%d valid=%d\n", (int)status, result.valid);
  return 0;
}
```

## Compile and run

From the working directory containing `host/`, `SyntheticUARTChecks/` and `ErdiLRF-0.1.1/`:

```sh
c++ -std=c++11 -Ihost/shim -ISyntheticUARTChecks -IErdiLRF-0.1.1/src host/native-synthetic-check.cpp ErdiLRF-0.1.1/src/ErdiLRF.cpp -o synthetic-check
./synthetic-check
```

The runner checks the checksum, raw values, two unit conversions and the corrupt-frame result with assertions before completing successfully. Expected output:

```
SYNTHETIC LRF50H status=0 raw=4354 metres=43.540
SYNTHETIC LRF50VB status=0 raw=4354 metres=4.354
SYNTHETIC CORRUPT status=1 valid=0
```

Changing the final byte with XOR makes the frame invalid. The parser discards it and continues waiting. With no valid replacement in this finite stream, it returns `ERDI_ERR_TIMEOUT` (`1`), not a distinct checksum-error result.

## Interpret the helper's limits

`SyntheticStream` consumes driver writes without transmitting them to hardware. Its input is an in-memory buffer. The host `millis()` stub advances a deterministic counter on every call; it does not represent elapsed wall-clock milliseconds.

The shims provide only enough Arduino/Stream behavior for this example. They do not reproduce electrical signals, UART timing, a module's response to commands or the complete Arduino runtime. Do not use them in firmware.

The optional Arduino sketch in the source bundle has a different output format for the invalid case: it prints the status only. The `valid=0` line above comes from this host runner. A previous Uno-target compile was a compile-only check, not a board upload or a sensor test.
