# Test a UART rangefinder parser before connecting hardware

A frame can pass its checksum and still turn into a distance that is wrong by a factor of ten. The missing piece is often the exact model's unit, rather than the serial transport.

We feed the same synthetic bytes into two model definitions in the published **ErdiLRF 0.1.1 Arduino library**, then corrupt the checksum to check that invalid input does not become a measurement. No sensor, target or module UART is needed.

**Disclosure:** We are the ERDILRF team at ERDI TECH LTD, the manufacturer associated with the library. The examples use generated bytes. They are software checks, not physical range, accuracy or compatibility tests.

## What the check covers

The library accepts an Arduino `Stream`. A small in-memory stream can therefore supply input bytes without connecting a rangefinder. Writes from the driver are consumed by the test helper and do not reach a module.

We use the library's `ERDI_LRF50H` and `ERDI_LRF50VB` definitions. In version 0.1.1, their distance conversion divides the raw count by 100 and 1,000 respectively. This is a comparison of the published software definitions; use the delivered unit's controlled manual to confirm a real integration.

The chosen input is `5C 02 11 EC`. The two distance bytes represent the synthetic raw count 4,354. The helper `erdiCheckSumB()` produces `EC` from `02 11`. Changing that last byte leaves the input without a valid frame.

## Install the published library

In Arduino IDE, open Library Manager, search for **ErdiLRF**, and select **0.1.1**. The same version is listed in the [Arduino library index](https://downloads.arduino.cc/libraries/library_index.json.gz) and [PlatformIO Registry](https://registry.platformio.org/libraries/erdi-tech/ErdiLRF).

For Arduino CLI:

```sh
arduino-cli lib update-index
arduino-cli lib install "ErdiLRF@0.1.1"
```

The version number matters: these checks describe 0.1.1. A later library release may change its implementation or documented limits.

## Add an in-memory input stream

Create a sketch named `SyntheticUARTChecks`. Add a tab/file named `SyntheticFrame.h` with the following code:

```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

```

The helper implements only a finite input buffer and an output sink. Its timeout keeps a corrupt or incomplete input from waiting indefinitely. It does not simulate electrical levels, UART timing or a real device's response to commands.

## Run the three cases

Put this in `SyntheticUARTChecks.ino`:

```cpp
#include "SyntheticFrame.h"

void showSynthetic(const char *label, ErdiModel model, const uint8_t frame[4]) {
  ErdiMeasurement measurement;
  ErdiStatus status = decodeSynthetic(model, frame, &measurement);
  Serial.print(label);
  Serial.print(" status=");
  Serial.print((int)status);
  if (status == ERDI_OK && measurement.valid) {
    Serial.print(" raw=");
    Serial.print(measurement.raw);
    Serial.print(" metres=");
    Serial.print(measurement.metres, 3);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("SYNTHETIC INPUT - no sensor measurement");

  uint8_t frame[4] = {0x5C, 0x02, 0x11, 0x00};
  frame[3] = erdiCheckSumB(&frame[1], 2);
  showSynthetic("LRF50H", ERDI_LRF50H, frame);
  showSynthetic("LRF50VB", ERDI_LRF50VB, frame);

  frame[3] ^= 0x01;
  showSynthetic("CORRUPT", ERDI_LRF50H, frame);
}

void loop() {}

```

The sketch uses `Serial` only for its console output at 115200. That is the console setting, not a statement about either sensor's delivered UART setting. Keep rangefinder hardware disconnected for this test.

To compile for an Arduino Uno with its AVR core installed:

```sh
arduino-cli compile --fqbn arduino:avr:uno SyntheticUARTChecks
```

Our verification build used Arduino CLI 1.5.1, AVR core 1.8.8 and a native ARM64 AVR-GCC 14.2.0 toolchain on macOS. It used 6,724 bytes of program storage and 308 bytes of static RAM. The sketch was compiled, not uploaded to a board.

Select the board you actually use when building a different target. A successful compile establishes that source/compiler/target combination; it does not establish electrical or hardware compatibility with a module.

## Read the result correctly

Our host-side execution of `decodeSynthetic()` with the exact published 0.1.1 C++ source produced:

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

These numbers came from generated bytes, not measurements. The valid cases demonstrate the model-specific conversion. In the corrupt case, the driver discards the invalid frame and waits for another one. Because the finite stream contains no valid replacement, it returns `ERDI_ERR_TIMEOUT`, whose value in this release is `1`.

Check the returned status before using `measurement.metres`. A timeout does not by itself distinguish a disconnected wire, a baud mismatch, incomplete input or discarded bad frames.

## What remains to check on real hardware

Before replacing the synthetic stream with a board UART, confirm the exact model, controlled manual revision, delivered interface, supply, TX/RX logic levels, baud setting and grounding. Retain raw receive bytes and the model/configuration used to interpret them.

The library documents unresolved source discrepancies, including an LRF50VB command-table/checksum mismatch. This in-memory exercise neither sends those commands to hardware nor resolves that discrepancy. It also does not establish ROS 2, PX4, ArduPilot, all-board or all-model compatibility.

The source and examples are available in [ErdiTech/ErdiLRF](https://github.com/ErdiTech/ErdiLRF). The library is MIT licensed; keep its license when redistributing it. The small test helper and sketch in this article are also provided under MIT.

For model documents or configuration questions, use the [ERDILRF catalog](https://erdilrf.com/models/) or [contact page](https://erdilrf.com/contact/). Technical contact: [tommy@erdimail.com](mailto:tommy@erdimail.com).
