Exercise: OneWire Sensor Class

Download Monolithic Sensor Implementation

Test Monolithic Implementation

  • Setup toolchain (if not yet done): Cross Toolchain Setup

  • Build as described in CMake: Cross Build

    In short (please supply the paths from your situation - /tmp/build and ~/source are only placeholders),

    $ mkdir /tmp/build/                       # <--- create build directory
    $ cd /tmp/build/                          # <--- cd into it
    $ cmake -DCMAKE_TOOLCHAIN_FILE=/home/jfasch/armv8-rpi4-linux-gnueabihf.cmake ~/source/
    ... roedel ...
    $ make
    
  • Transfer to Raspberry,

    $ scp -P 2020 /tmp/build/path/to/your/programs/onewire-temperature firstname.lastname@jfasch.bounceme.net:
    
  • Test it

    $ ssh -p 2020 firstname.lastname@jfasch.bounceme.net ./onewire-temperature
    ./onewire-temperature <filename> <interval>
    
    $ ssh -p 2020 firstname.lastname@jfasch.bounceme.net ./onewire-temperature /sys/bus/w1/devices/28-02131d959eaa/temperature 1
    20687
    20687
    ...
    

class W1Sensor

  • Add the following test to your test suite (i.e., register it a another source file in CMakeLists.txt)

  • To make it run, create a pair of files (sensor-w1.{h,cpp}) in your library directory (again, CMakeLists.txt)

  • Fix test failures until green

Note

The sensor implementation is in no way tied to the Raspberry. All it does is read a file, and that can be done on the development machine (a PC likely) just as well.

#include <gtest/gtest.h>

#include <sensor-w1.h>

#include <cstdlib>
#include <unistd.h>

#include <stdexcept>

using namespace std;


// fixture class: supply a temporary file, plus a method
// write_temperature() thaht derived classes can call
struct w1_sensor_suite : public ::testing::Test
{
    void SetUp() override
    {
        char filename_pattern[] = "w1_sensor_suite-XXXXXX";
        
        fd = mkstemp(filename_pattern);
        if (fd == -1)
            throw runtime_error("nix mkstemp()");

        filename = filename_pattern;
    }

    void TearDown() override
    {
        if (fd != -1) {
            close(fd);
            unlink(filename.c_str());
        }
    }

    void change_temperature(double temperature)
    {
        unsigned temp_milli = temperature * 1000;

        string content = to_string(temp_milli);

        off_t pos = ::lseek(fd, 0, SEEK_SET);
        ASSERT_EQ(pos, 0);

        ssize_t nwritten = ::write(fd, content.c_str(), content.size());
        ASSERT_EQ(nwritten, content.size());
    }


    int fd;
    string filename;
};

TEST_F(w1_sensor_suite, test_read_sensor)
{
    W1Sensor sensor(filename);                 // <--- using filename from w1_sensor_suite fixture
    double temperature;

    change_temperature(42.666);                // <--- change temperature
    temperature = sensor.get_temperature();    // <--- read temperature
    ASSERT_FLOAT_EQ(temperature, 42.666);

    change_temperature(36.5);                  // <--- change temperature
    temperature = sensor.get_temperature();    // <--- read temperature
    ASSERT_FLOAT_EQ(temperature, 36.5);
}

Refactoring

Modify onewire-temperature.cpp to not use any file operations. Rather, #include <sensor-w1.h> and use that instead.

Testing

  • When done, test it on the Pi like above