feat: Layer 2 device library system with TMP36 reference driver
Add embedded device library registry with full lifecycle management, automated test integration, and pin assignment workflow. Library system: - Library registry embedded in binary via include_dir! (same as templates) - library.toml metadata format: name, version, bus type, pins, provided files - anvil add <name> extracts headers to lib/drivers/<name>/, test files to test/ - anvil remove <name> cleans up all files, config entries, and include paths - anvil lib lists installed libraries with status - anvil lib --available shows registry with student-friendly wiring summary - [libraries] section in .anvil.toml tracks installed libraries and versions - CMake auto-discovers lib/drivers/*/ for include paths at configure time TMP36 analog temperature sensor (reference implementation): - TempSensor abstract interface (readCelsius/readFahrenheit/readRaw) - Tmp36Analog: real hardware impl via Hal::analogRead with configurable Vref - Tmp36Mock: programmable values, read counting, no hardware needed - Tmp36Sim: deterministic noise via seeded LCG for repeatable system tests - test_tmp36.cpp: 21 Google Test cases covering mock, analog, sim, polymorphism - TMP36 formula: voltage_mV = raw * Vref_mV / 1024, temp_C = (mV - 500) / 10 Automated test integration: - Library test files (test_*.cpp) route to test/ during extraction - CMakeLists.txt auto-discovers test_*.cpp via GLOB, builds each as own target - anvil remove cleans up test files alongside driver headers - Zero manual CMake editing: add library, run test --clean, tests appear Pin assignment integration: - anvil add <name> --pin A0 does extract + pin assignment in one step - Without --pin, prints step-by-step wiring guidance with copy-paste commands - anvil pin --audit flags installed libraries with unassigned pins - Audit works even with zero existing pin assignments (fixed early-return bug) - LibraryMeta helpers: wiring_summary(), pin_roles(), default_mode() - Bus-aware guidance: analog pins, I2C bus registration, SPI with CS selection UX improvements: - anvil lib --available shows "Needs: 1 analog pin (e.g. A0)" not raw metadata - anvil add prints app code example, test code example, and next step - anvil pin --audit prints exact commands to resolve missing library pins - anvil remove shows test file deletion in output Files added: - libraries/tmp36/library.toml - libraries/tmp36/src/tmp36.h, tmp36_analog.h, tmp36_mock.h, tmp36_sim.h - libraries/tmp36/src/test_tmp36.cpp - src/library/mod.rs Files modified: - src/lib.rs, src/main.rs, src/commands/mod.rs - src/commands/lib.rs (add/remove/list/list_available with --pin support) - src/commands/pin.rs (audit library pin warnings, print_library_pin_warnings) - src/project/config.rs (libraries HashMap field) - templates/basic/test/CMakeLists.txt.tmpl (driver + test auto-discovery) Tests: 254 total (89 unit + 165 integration) - 12 library/mod.rs unit tests (registry, extraction, helpers) - 2 commands/lib.rs unit tests (class name derivation) - 30+ new integration tests covering library lifecycle, pin integration, audit flows, file routing, CMake discovery, config roundtrips, ASCII compliance, polymorphism contracts, and idempotent add/remove cycles
This commit is contained in:
15
libraries/tmp36/library.toml
Normal file
15
libraries/tmp36/library.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[library]
|
||||
name = "tmp36"
|
||||
version = "0.1.0"
|
||||
description = "TMP36 analog temperature sensor"
|
||||
|
||||
[requires]
|
||||
bus = "analog"
|
||||
pins = ["data"]
|
||||
|
||||
[provides]
|
||||
interface = "tmp36.h"
|
||||
implementation = "tmp36_analog.h"
|
||||
mock = "tmp36_mock.h"
|
||||
simulation = "tmp36_sim.h"
|
||||
test = "test_tmp36.cpp"
|
||||
252
libraries/tmp36/src/test_tmp36.cpp
Normal file
252
libraries/tmp36/src/test_tmp36.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* TMP36 Driver Tests
|
||||
*
|
||||
* Auto-generated by: anvil add tmp36
|
||||
* These tests verify the TMP36 driver mock and simulation without
|
||||
* any hardware. They run alongside your unit and system tests.
|
||||
*
|
||||
* To run: ./test.sh (all tests)
|
||||
* ./test.sh --system (skips these -- use no filter to include)
|
||||
* ./test.sh --unit (skips these -- use no filter to include)
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "mock_arduino.h"
|
||||
#include "sim_hal.h"
|
||||
#include "tmp36.h"
|
||||
#include "tmp36_analog.h"
|
||||
#include "tmp36_mock.h"
|
||||
#include "tmp36_sim.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock: basic functionality
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class Tmp36MockTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
mock_arduino_reset();
|
||||
}
|
||||
|
||||
Tmp36Mock sensor;
|
||||
};
|
||||
|
||||
TEST_F(Tmp36MockTest, DefaultsToRoomTemperature) {
|
||||
float temp = sensor.readCelsius();
|
||||
EXPECT_NEAR(temp, 22.0f, 0.01f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, SetTemperatureReturnsExactValue) {
|
||||
sensor.setTemperature(37.5f);
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), 37.5f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, FahrenheitConversion) {
|
||||
sensor.setTemperature(0.0f);
|
||||
EXPECT_NEAR(sensor.readFahrenheit(), 32.0f, 0.01f);
|
||||
|
||||
sensor.setTemperature(100.0f);
|
||||
EXPECT_NEAR(sensor.readFahrenheit(), 212.0f, 0.01f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, BoilingPointConversion) {
|
||||
sensor.setTemperature(100.0f);
|
||||
EXPECT_NEAR(sensor.readFahrenheit(), 212.0f, 0.01f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, NegativeTemperature) {
|
||||
sensor.setTemperature(-10.0f);
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), -10.0f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, ReadCountTracking) {
|
||||
EXPECT_EQ(sensor.readCount(), 0);
|
||||
sensor.readCelsius();
|
||||
sensor.readCelsius();
|
||||
sensor.readRaw();
|
||||
EXPECT_EQ(sensor.readCount(), 3);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, ReadCountReset) {
|
||||
sensor.readCelsius();
|
||||
sensor.readCelsius();
|
||||
sensor.resetReadCount();
|
||||
EXPECT_EQ(sensor.readCount(), 0);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36MockTest, SetRawReturnsExactValue) {
|
||||
sensor.setRaw(512);
|
||||
EXPECT_EQ(sensor.readRaw(), 512);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Analog: real implementation via SimHal
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class Tmp36AnalogTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
mock_arduino_reset();
|
||||
}
|
||||
|
||||
SimHal hal;
|
||||
};
|
||||
|
||||
TEST_F(Tmp36AnalogTest, RoomTemperatureReading) {
|
||||
// 22 C -> 720 mV -> raw = 720 * 1024 / 5000 = 147.5 -> ~148
|
||||
Tmp36Analog sensor(&hal, A0, 5.0f);
|
||||
hal.setAnalog(A0, 148);
|
||||
|
||||
float temp = sensor.readCelsius();
|
||||
// 148 * 5000/1024 = 722.6 mV -> (722.6 - 500) / 10 = 22.26 C
|
||||
EXPECT_NEAR(temp, 22.26f, 0.1f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36AnalogTest, FreezingPoint) {
|
||||
// 0 C -> 500 mV -> raw = 500 * 1024 / 5000 = 102.4 -> ~102
|
||||
Tmp36Analog sensor(&hal, A0, 5.0f);
|
||||
hal.setAnalog(A0, 102);
|
||||
|
||||
float temp = sensor.readCelsius();
|
||||
EXPECT_NEAR(temp, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36AnalogTest, HighTemperature) {
|
||||
// 50 C -> 1000 mV -> raw = 1000 * 1024 / 5000 = 204.8 -> ~205
|
||||
Tmp36Analog sensor(&hal, A0, 5.0f);
|
||||
hal.setAnalog(A0, 205);
|
||||
|
||||
float temp = sensor.readCelsius();
|
||||
EXPECT_NEAR(temp, 50.0f, 1.0f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36AnalogTest, ThreeVoltReference) {
|
||||
// Same raw value, different ref voltage changes the result
|
||||
Tmp36Analog sensor_5v(&hal, A0, 5.0f);
|
||||
Tmp36Analog sensor_3v(&hal, A0, 3.3f);
|
||||
hal.setAnalog(A0, 200);
|
||||
|
||||
float temp_5v = sensor_5v.readCelsius();
|
||||
float temp_3v = sensor_3v.readCelsius();
|
||||
|
||||
// 3.3V ref reads higher mV per count, so higher temperature
|
||||
// Actually the opposite: lower ref means each count = fewer mV
|
||||
EXPECT_NE(temp_5v, temp_3v);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36AnalogTest, ReadRawReturnsAnalogValue) {
|
||||
Tmp36Analog sensor(&hal, A0, 5.0f);
|
||||
hal.setAnalog(A0, 512);
|
||||
EXPECT_EQ(sensor.readRaw(), 512);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36AnalogTest, DifferentPin) {
|
||||
// Can use any analog pin
|
||||
Tmp36Analog sensor(&hal, A2, 5.0f);
|
||||
hal.setAnalog(A2, 148);
|
||||
|
||||
float temp = sensor.readCelsius();
|
||||
EXPECT_NEAR(temp, 22.26f, 0.1f);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Simulation: noise and determinism
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class Tmp36SimTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
mock_arduino_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Tmp36SimTest, ReturnsValuesNearBase) {
|
||||
Tmp36Sim sensor(25.0f, 1.0f);
|
||||
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
float temp = sensor.readCelsius();
|
||||
EXPECT_GE(temp, 24.0f) << "Reading " << i << " too low";
|
||||
EXPECT_LE(temp, 26.0f) << "Reading " << i << " too high";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Tmp36SimTest, ZeroNoiseReturnsExact) {
|
||||
Tmp36Sim sensor(25.0f, 0.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), 25.0f);
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), 25.0f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36SimTest, DeterministicWithSameSeed) {
|
||||
Tmp36Sim s1(25.0f, 1.0f);
|
||||
Tmp36Sim s2(25.0f, 1.0f);
|
||||
s1.setSeed(99);
|
||||
s2.setSeed(99);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EXPECT_FLOAT_EQ(s1.readCelsius(), s2.readCelsius())
|
||||
<< "Reading " << i << " should match with same seed";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Tmp36SimTest, DifferentSeedsDifferentValues) {
|
||||
Tmp36Sim s1(25.0f, 1.0f);
|
||||
Tmp36Sim s2(25.0f, 1.0f);
|
||||
s1.setSeed(1);
|
||||
s2.setSeed(2);
|
||||
|
||||
// At least one reading should differ
|
||||
bool any_differ = false;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (s1.readCelsius() != s2.readCelsius()) {
|
||||
any_differ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(any_differ);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36SimTest, BaseTemperatureChange) {
|
||||
Tmp36Sim sensor(20.0f, 0.0f);
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), 20.0f);
|
||||
|
||||
sensor.setBaseTemperature(40.0f);
|
||||
EXPECT_FLOAT_EQ(sensor.readCelsius(), 40.0f);
|
||||
}
|
||||
|
||||
TEST_F(Tmp36SimTest, RawValueMatchesTemperature) {
|
||||
Tmp36Sim sensor(25.0f, 0.0f);
|
||||
|
||||
// 25 C -> 750 mV -> raw = 750 * 1024 / 5000 = 153.6 -> ~153
|
||||
int raw = sensor.readRaw();
|
||||
EXPECT_NEAR(raw, 153, 2);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Polymorphism: all impls work through TempSensor pointer
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST(Tmp36PolymorphismTest, AllImplsWorkThroughBasePointer) {
|
||||
mock_arduino_reset();
|
||||
SimHal hal;
|
||||
hal.setAnalog(A0, 148);
|
||||
|
||||
Tmp36Analog analog_sensor(&hal, A0, 5.0f);
|
||||
Tmp36Mock mock_sensor;
|
||||
Tmp36Sim sim_sensor(22.0f, 0.0f);
|
||||
|
||||
mock_sensor.setTemperature(22.0f);
|
||||
|
||||
TempSensor* sensors[] = { &analog_sensor, &mock_sensor, &sim_sensor };
|
||||
|
||||
for (auto* s : sensors) {
|
||||
float c = s->readCelsius();
|
||||
float f = s->readFahrenheit();
|
||||
int raw = s->readRaw();
|
||||
|
||||
EXPECT_GT(c, 10.0f);
|
||||
EXPECT_LT(c, 40.0f);
|
||||
EXPECT_GT(f, 50.0f);
|
||||
EXPECT_GE(raw, 0);
|
||||
}
|
||||
}
|
||||
54
libraries/tmp36/src/tmp36.h
Normal file
54
libraries/tmp36/src/tmp36.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef TMP36_H
|
||||
#define TMP36_H
|
||||
|
||||
/*
|
||||
* TMP36 Temperature Sensor -- Abstract Interface
|
||||
*
|
||||
* This is the contract that your application code depends on. It does
|
||||
* not know or care whether the temperature comes from a real TMP36
|
||||
* wired to an analog pin, a test mock with canned values, or a
|
||||
* simulation with realistic noise.
|
||||
*
|
||||
* Three implementations ship with this driver:
|
||||
* tmp36_analog.h -- Real hardware via Hal::analogRead()
|
||||
* tmp36_mock.h -- Test mock with programmable values
|
||||
* tmp36_sim.h -- Simulation with configurable noise
|
||||
*
|
||||
* Usage in application code:
|
||||
* #include "tmp36.h"
|
||||
*
|
||||
* class ThermostatApp {
|
||||
* public:
|
||||
* ThermostatApp(Hal* hal, TempSensor* sensor)
|
||||
* : hal_(hal), sensor_(sensor) {}
|
||||
*
|
||||
* void update() {
|
||||
* float temp = sensor_->readCelsius();
|
||||
* if (temp > threshold_) {
|
||||
* hal_->digitalWrite(FAN_PIN, HIGH);
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* Generated by Anvil -- https://github.com/nexus-workshops/anvil
|
||||
*/
|
||||
|
||||
class TempSensor {
|
||||
public:
|
||||
virtual ~TempSensor() = default;
|
||||
|
||||
/// Read temperature in degrees Celsius.
|
||||
virtual float readCelsius() = 0;
|
||||
|
||||
/// Read temperature in degrees Fahrenheit.
|
||||
/// Default implementation converts from Celsius.
|
||||
virtual float readFahrenheit() {
|
||||
return readCelsius() * 9.0f / 5.0f + 32.0f;
|
||||
}
|
||||
|
||||
/// Read the raw ADC value (0-1023 for 10-bit).
|
||||
/// Useful for debugging or custom calibration.
|
||||
virtual int readRaw() = 0;
|
||||
};
|
||||
|
||||
#endif // TMP36_H
|
||||
48
libraries/tmp36/src/tmp36_analog.h
Normal file
48
libraries/tmp36/src/tmp36_analog.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef TMP36_ANALOG_H
|
||||
#define TMP36_ANALOG_H
|
||||
|
||||
#include "tmp36.h"
|
||||
#include "hal.h"
|
||||
|
||||
/*
|
||||
* TMP36 -- Real hardware implementation (analog read).
|
||||
*
|
||||
* The TMP36 outputs a voltage proportional to temperature:
|
||||
* - 10 mV per degree Celsius
|
||||
* - 500 mV offset at 0 C (so 750 mV = 25 C)
|
||||
* - Range: -40 C to +125 C
|
||||
*
|
||||
* Wiring:
|
||||
* TMP36 pin 1 (left) -> 5V (or 3.3V)
|
||||
* TMP36 pin 2 (middle) -> Analog input (A0 by default)
|
||||
* TMP36 pin 3 (right) -> GND
|
||||
*
|
||||
* If your board runs at 3.3V, pass 3.3f as ref_voltage.
|
||||
*/
|
||||
class Tmp36Analog : public TempSensor {
|
||||
public:
|
||||
/// Create a TMP36 sensor on the given analog pin.
|
||||
/// ref_voltage: board reference voltage (5.0 for Uno, 3.3 for Due/ESP).
|
||||
Tmp36Analog(Hal* hal, uint8_t pin, float ref_voltage = 5.0f)
|
||||
: hal_(hal)
|
||||
, pin_(pin)
|
||||
, ref_mv_(ref_voltage * 1000.0f)
|
||||
{}
|
||||
|
||||
float readCelsius() override {
|
||||
int raw = hal_->analogRead(pin_);
|
||||
float mv = (float)raw * ref_mv_ / 1024.0f;
|
||||
return (mv - 500.0f) / 10.0f;
|
||||
}
|
||||
|
||||
int readRaw() override {
|
||||
return hal_->analogRead(pin_);
|
||||
}
|
||||
|
||||
private:
|
||||
Hal* hal_;
|
||||
uint8_t pin_;
|
||||
float ref_mv_;
|
||||
};
|
||||
|
||||
#endif // TMP36_ANALOG_H
|
||||
60
libraries/tmp36/src/tmp36_mock.h
Normal file
60
libraries/tmp36/src/tmp36_mock.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef TMP36_MOCK_H
|
||||
#define TMP36_MOCK_H
|
||||
|
||||
#include "tmp36.h"
|
||||
|
||||
/*
|
||||
* TMP36 -- Test mock with programmable values.
|
||||
*
|
||||
* Use this in tests to control exactly what temperature your
|
||||
* application sees, without any real hardware.
|
||||
*
|
||||
* Example:
|
||||
* Tmp36Mock sensor;
|
||||
* sensor.setTemperature(30.0f);
|
||||
*
|
||||
* ThermostatApp app(&sim, &sensor);
|
||||
* app.update();
|
||||
*
|
||||
* EXPECT_EQ(sim.getPin(FAN_PIN), HIGH); // fan should be on
|
||||
*
|
||||
* You can also track how many times the sensor was read:
|
||||
* sensor.resetReadCount();
|
||||
* app.update();
|
||||
* EXPECT_EQ(sensor.readCount(), 1);
|
||||
*/
|
||||
class Tmp36Mock : public TempSensor {
|
||||
public:
|
||||
/// Set the temperature that readCelsius() returns.
|
||||
void setTemperature(float celsius) {
|
||||
temp_c_ = celsius;
|
||||
}
|
||||
|
||||
/// Set the raw ADC value that readRaw() returns.
|
||||
void setRaw(int raw) {
|
||||
raw_ = raw;
|
||||
}
|
||||
|
||||
float readCelsius() override {
|
||||
++read_count_;
|
||||
return temp_c_;
|
||||
}
|
||||
|
||||
int readRaw() override {
|
||||
++read_count_;
|
||||
return raw_;
|
||||
}
|
||||
|
||||
/// How many times has the sensor been read?
|
||||
int readCount() const { return read_count_; }
|
||||
|
||||
/// Reset the read counter.
|
||||
void resetReadCount() { read_count_ = 0; }
|
||||
|
||||
private:
|
||||
float temp_c_ = 22.0f; // Default: room temperature
|
||||
int raw_ = 153; // ~22 C at 5V reference
|
||||
int read_count_ = 0;
|
||||
};
|
||||
|
||||
#endif // TMP36_MOCK_H
|
||||
74
libraries/tmp36/src/tmp36_sim.h
Normal file
74
libraries/tmp36/src/tmp36_sim.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef TMP36_SIM_H
|
||||
#define TMP36_SIM_H
|
||||
|
||||
#include "tmp36.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
/*
|
||||
* TMP36 -- Simulation with realistic noise.
|
||||
*
|
||||
* Unlike the mock (which returns exact values), the simulator adds
|
||||
* configurable noise to a base temperature. This is useful for
|
||||
* system tests that need to verify your code handles real-world
|
||||
* sensor jitter, such as:
|
||||
*
|
||||
* - Averaging/filtering algorithms
|
||||
* - Hysteresis thresholds (so the fan doesn't chatter on/off)
|
||||
* - Out-of-range detection
|
||||
*
|
||||
* Example:
|
||||
* Tmp36Sim sensor(22.0f, 0.5f); // 22 C +/- 0.5 C noise
|
||||
*
|
||||
* // Each read returns a slightly different value
|
||||
* float t1 = sensor.readCelsius(); // maybe 22.3
|
||||
* float t2 = sensor.readCelsius(); // maybe 21.8
|
||||
*
|
||||
* // Simulate outdoor temperature swing
|
||||
* sensor.setBaseTemperature(35.0f);
|
||||
*/
|
||||
class Tmp36Sim : public TempSensor {
|
||||
public:
|
||||
/// Create a simulated sensor.
|
||||
/// base_temp: center temperature in Celsius
|
||||
/// noise: maximum deviation in either direction (Celsius)
|
||||
Tmp36Sim(float base_temp = 22.0f, float noise = 0.5f)
|
||||
: base_temp_(base_temp)
|
||||
, noise_range_(noise)
|
||||
, seed_(42)
|
||||
{}
|
||||
|
||||
/// Change the base temperature (simulates environment change).
|
||||
void setBaseTemperature(float celsius) { base_temp_ = celsius; }
|
||||
|
||||
/// Change the noise amplitude.
|
||||
void setNoise(float range) { noise_range_ = range; }
|
||||
|
||||
/// Seed the random number generator for repeatable tests.
|
||||
void setSeed(unsigned int seed) { seed_ = seed; }
|
||||
|
||||
float readCelsius() override {
|
||||
float noise = noise_range_ * (2.0f * nextRandom() - 1.0f);
|
||||
return base_temp_ + noise;
|
||||
}
|
||||
|
||||
int readRaw() override {
|
||||
float temp_c = readCelsius();
|
||||
float mv = temp_c * 10.0f + 500.0f;
|
||||
return (int)(mv * 1024.0f / 5000.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
float base_temp_;
|
||||
float noise_range_;
|
||||
unsigned int seed_;
|
||||
|
||||
/// Simple LCG random in [0.0, 1.0).
|
||||
/// Deterministic -- same seed gives same sequence.
|
||||
float nextRandom() {
|
||||
seed_ = seed_ * 1103515245 + 12345;
|
||||
return (float)((seed_ >> 16) & 0x7FFF) / 32768.0f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TMP36_SIM_H
|
||||
Reference in New Issue
Block a user