Embedded Computing 1 (STECE-2024): Summer#

2026-02-22: Intro: OS And C++ (Live Demo)#

Livehacked by teacher

  • Login to Pi at home: ssh -p 2022 jfasch.bounceme.net

$ ls -l /sys/class/hwmon/
$ ls -l /sys/class/hwmon/hwmon2/
#include <iostream>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>

#include <string>
#include <stdexcept>


class Thermometer
{
public:
    Thermometer(const std::string& filename)
    {
        _fd = open(filename.c_str(), O_RDONLY);
        if (_fd == -1)
            throw std::runtime_error("nix open");
    }

    ~Thermometer()
    {
        close(_fd);
    }

    double get_temperature() const
    {
        char buffer[64];
        ssize_t nbytes = read(_fd, buffer, sizeof(buffer)-1);
        if (nbytes == -1)
            throw std::runtime_error("nix read");

        off_t newpos = lseek(_fd, 0, SEEK_SET);
        if (newpos == -1) {
            throw std::runtime_error("nix lseek64");
        }

        buffer[nbytes] = '\0';
        int milli_celsius = std::stoi(buffer);
        double celsius = milli_celsius / 1000.0;
    
        return celsius;
    }

private:
    int _fd;
};


int main(int argc, char** argv)
{
    if (argc != 2) {
        std::cerr << "nix zwei argumente" << std::endl;
        return 1;
    }
    const char* filename = argv[1];
    Thermometer thermo(filename);

    while (true) {
        std::cout << thermo.get_temperature() << std::endl;

        timespec interval = { 1, 0 };
        int rv = nanosleep(&interval, nullptr);
        if (rv == -1) {
            std::cerr << "nix sleep?" << std::endl;
            return 1;
        }

    }
    
    return 0;
}

2026-02-2{3,4}: Prepare Work Environment#

Install OS#

Current options …

  • Use Egon Teiniker’s Debian VirtualBox image from previous semesters

    • Pro: already there

    • Con: compiler version might be too low for our C++ topics

  • Use Windows Subsystem for Linux (WSL2), see Windows Subsystem for Linux (WSL)

    • Pro

      • Seamless integration with Windows

      • VS Code extension(s) available

      • The way to go

    • Con

      • No Linux GUI program possible (yet)

  • Use MacOS

    • Pro: already there

    • Con: not Linux, for that matter

  • Use Linux

    • Pro: best

    • Con: none

Programming Environment, Project#

2026-03-02 (3VO): File I/O And Systems Programming, Homework#

Permissions Intro#

From Permissions: Mode, User and Group Ownership

Program Entry And Exit#

System Calls Intro#

File IO#

From Files And File Descriptors

Homework#

2026-03-09 (3UE*2): File I/O (Homework)#

Continuing with homework from last time around …

  • Trainer pushes missing artifacts (argh)

  • Trainer live-hacks solution

2026-03-13 (3VO): Git (SSH), C++ Intro#

Basic git Workflow: add, commit, push (, pull)#

  • View changes

    Current working directory somewhere inside the tree,

    $ git status
    ...
    
  • git add changes: stage for next commit

    $ git add file.h file.cpp
    ...
    

    Review repo situation

    $ git status
    ...
    
  • git commit what you staged

    Either non-interactive (giving the commit message as a commandline parameter)

    $ git commit -m 'frobozz the foobar'
    

    Or letting git pop up your favorite $EDITOR

    $ git commit
    
  • git push

  • git pull

SSH, And Using It For Git Repository Access#

From SSH: Secure Shell:

Exercise: Key Pair, Deployed To Codeberg#

  • Create key pair. Leave passphrase empty (else you’ll have to type it in over and over, just like the HTTPS password)

  • Send to trainer

    • Public key (id_rsa.pub)

    • Codeberg account name

  • Deploy SSH public key on Codeberg (account (icon above right) -> “Settings” -> “SSH / GPG keys”)

  • You have a clone of your fork of the upstream repo; change that clone’s upstream URL from HTTPS to SSH.

    First, look:

    $ git remote
    origin
    $ git remote -v
    origin     https://codeberg.org/_codebergaccountname_/FH-STECE2024.git (fetch)
    origin     https://codeberg.org/_codebergaccountname_/FH-STECE2024.git (push)
    

    Then set:

    $ git remote set-url origin ssh://git@codeberg.org/_codebergaccountname_/FH-STECE2024.git
    

Distributed git: Update Your Fork From Upstream#

../../../../../../_images/forgejo-fresh-fork-and-clone.jpg

Current situation#

../../../../../../_images/forgejo-update-fork.jpg

Wanted: merge changes from upstream#

  • Create a remote for upstream https://codeberg.org/jfasch/FH-STECE2024.git

    $ git remote add upstream https://codeberg.org/jfasch/FH-STECE2024.git
    
    $ git remote -v
    origin     https://codeberg.org/_codebergaccountname_/FH-STECE2024.git (fetch)
    origin     https://codeberg.org/_codebergaccountname_/FH-STECE2024.git (push)
    upstream   https://codeberg.org/jfasch/FH-STECE2024.git (fetch)
    upstream   https://codeberg.org/jfasch/FH-STECE2024.git (push)
    
  • Fetch from upstream

    $ git fetch upstream
    ... roedel ...
    
  • Merge upstream/master into your local master branch

    Check that your current branch is master,

    $ git branch
    * master
    

    Merge,

    $ git merge upstream/master
    

    Note that this is not always so easy - you might have to resolve conflicts.

    Push to default location - your fork,

    $ git push
    
  • Shorthand: git pull. This is the same as fetch followed by merge

2026-03-16 (3UE*2): Exercise: PWM Controller (TDD)#

See Homework: PWM Controller (2026-03-16)

2026-03-20 (3VO): cp-for-the-poor (Recap), C++ Intro#

Exercises#

  • Homework: cp-for-the-poor (2026-03-02)

    • Closed; was optional anyhow

    • List of pull requests

      • Morena_M (REJECTED): rejected: build/ added

      • johanneshranitzky (DONE): conflict marker committed

      • pholz (DONE): (sehr geil)

      • FarzanehN (REJECTED): unrelated changes (my-codeberg-name)

      • KoenigMaxi (REJECTED): exit status 130

    • ⟶ Complaint summary: build/ directory part of PR, unrelated changes, …

    • Sommer_r: strace session :-)

  • PWM exercise ongoing, questions

Commandline Repetition#

From The Shell (Bash - “Bourne Again Shell”) in Linux Basics:

Exercise

2026-03-23 (3UE*2): PWM Exercise, Shell Exercise#

  • Exercises: Create/Copy/Move/Remove

    Show an inline loop, reading temperature. Discuss the nature of true and false, and [. Transform into shell script. Initially without shebang, but 755, then explain interpreter line.

  • Bring PWM exercise to an end

2026-04-20 (3VO): C++ Intro#

From Data Encapsulation:

Spickzettel#

Original C#

#include <stdio.h>
#include <math.h>

struct point
{
    float x;
    float y;
};

void point_move(struct point* p, float x, float y)
{
    p->x += x;
    p->y += y;
}

float point_abs(const struct point* p)
{
    return sqrtf(p->x*p->x + p->y*p->y);
}

int main(void)
{
    struct point p;
    printf("point (%f,%f)\n", p.x, p.y);
    printf("abs %f\n", point_abs(&p));
    return 0;
}

Constructor#

  • Don’t leave anything uninitialized

  • this? Currently only used to disambiguate between two versions of x.

#include <stdio.h>
#include <math.h>

struct point
{
    point(float x, float y)
    {
        this->x = x;
        this->y = y;
    }

    float x;
    float y;
};

int main(void)
{
    point p(3,4);
    printf("point (%f,%f)\n", p.x, p.y);
    return 0;
}

Default Constructor#

  • People want point p; to have a defined outcome

  • ⟶ default constructor

#include <stdio.h>
#include <math.h>

struct point
{
public:
    point()
    {
        this->_x = 0;
        this->_y = 0;
    }
    point(float x, float y)
    {
        this->_x = x;
        this->_y = y;
    }

    float x() const { return this->_x; }
    float y() const { return this->_y; }

    void move(float x, float y)
    {
        this->_x += x;
        this->_y += y;
    }

    float abs() const
    {
        return sqrtf(this->_x*this->_x + this->_y*this->_y);
    }

private:
    float _x;
    float _y;
};

int main(void)
{
    point p;                                           // <-- default initialization
    printf("point (%f,%f)\n", p.x(), p.y());
    printf("abs %f\n", p.abs());
    return 0;
}

Non const Method: move()#

  • move() modifies a point

  • Explicit first parameter becomes implicit this

#include <stdio.h>
#include <math.h>

struct point
{
    point(float x, float y)
    {
        this->x = x;
        this->y = y;
    }

    void move(float x, float y)
    {
        this->x += x;
        this->y += y;
    }

    float x;
    float y;
};

int main(void)
{
    point p(3,4);
    printf("point (%f,%f)\n", p.x, p.y);
    p.move(1,1);
    printf("point (%f,%f)\n", p.x, p.y);
    return 0;
}

const Method: abs()#

  • Does not modify a point

  • const method

#include <stdio.h>
#include <math.h>

struct point
{
    point(float x, float y)
    {
        this->x = x;
        this->y = y;
    }

    void move(float x, float y)
    {
        this->x += x;
        this->y += y;
    }

    float abs() const
    {
        return sqrtf(this->x*this->x + this->y*this->y);
    }

    float x;
    float y;
};

int main(void)
{
    point p(3,4);
    printf("point (%f,%f)\n", p.x, p.y);
    printf("abs %f\n", p.abs());
    return 0;
}

Access Specifiers: public And private#

Use case: nobody should be able to fiddle with members x and y in an uncontrolled way!

A class definition may have access specifiers:

  • public: members visible to outside (default for struct)

  • protected: members visible to derived classes ⟶ a sign of implementation inheritance (discouraged)

  • private: members only visible to other members of same class (default for class) ⟶ access methods

  • Let’s remove the explicit this, btw.

#include <stdio.h>
#include <math.h>

class Point
{
public:
    Point(float x, float y)
    {
        _x = x;
        _y = y;
    }

    float x() const { return _x; }
    float y() const { return _y; }

    void move(float x, float y)
    {
        _x += x;
        _y += y;
    }

    float abs() const
    {
        return sqrtf(_x*_x + _y*_y);
    }

private:
    float _x;
    float _y;
};

int main(void)
{
    Point p(3,4);
    printf("point (%f,%f)\n", p.x(), p.y());
    printf("abs %f\n", p.abs());
    return 0;
}

Separate Compilation Units#

  • Class definition may contain method implementations

  • Expanded inline when called (entire code copied to caller)

  • Not space friendly for large methods

  • ⟶ Put into separate compilation unit and generate a real call

#include "point.h"
#include <stdio.h>

int main(void)
{
    Point p(3,4);
    printf("point (%f,%f)\n", p.x(), p.y());
    printf("abs %f\n", p.abs());
    return 0;
}
#pragma once

class Point
{
public:
    Point(float x, float y)
    {
        this->_x = x;
        this->_y = y;
    }

    float x() const { return this->_x; }
    float y() const { return this->_y; }

    void move(float x, float y);
    float abs() const;

private:
    float _x;
    float _y;
};
#include "point.h"
#include <math.h>

void Point::move(float x, float y)
{
    this->_x += x;
    this->_y += y;
}

float Point::abs() const
{
    return sqrtf(this->_x*this->_x + this->_y*this->_y);
}

2026-04-20+2026-04-24 (3UE*2): C++ Exercise#

Re-implement the PWM exercise in C++. The nonsensical Point example from 2026-04-20 can be taken as guidance.

Attention: for this work, please

  • Create a branch in you local copy (e.g. pwm-cpp)

  • Implement the feature on that branch. Check that you are on the correct branch!!

    $ git branch
    pwm-cpp
    
  • Push that branch to your fork on Codeberg when done

  • Send a pull request from that branch