mdwiki test starts
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2025-04-14 22:22:45 +02:00
parent 5c7ee2266a
commit b2249c06e9
143 changed files with 8463 additions and 215 deletions

View File

@ -0,0 +1,137 @@
<!--
title: Yet Another Debouncing Method
date: 2018-04-30
-->
You can find several approaches for debouncing mechanical switches on the Internet, some work better, some not so good.
One common approach is to ignore events in an ISR when they come too fast:<
```
void count() {
static uint32_t lastEvent = 0;
uint32_t currentEvent = micros();
if (currentEvent &gt; (lastEvent + configBlock.debounce)) {
lastEvent = currentEvent;
cnt++;
}
}
void setup() {
pinMode(REED_PIN, INPUT_PULLUP);
attachInterrupt(REED_PIN, count, FALLING);
}
```
This works very good when only the tipping of a switch is relevant.
When also the time the button was pressed is relevant and when it is especially necessary to distinguish between a short and a long press this approach doesn't work anymore.
Since I couldn't remember the approaches I read about earlier I've sketched this state machine:
![](/static/20180430110848869_0001.jpg)
(The double-lined states are action-states which send out the related information.)
At least for me, this approach is working very reliable so far, I'm quite happy with it.
```
enum tPressedState { psHIGH, psLOW, psACCEPTED_LOW, psLONG_START, psLONG_CONT, psLONG_CONT_SEND, psLONG_END, psSHORT, psINVALID };
typedef struct {
uint8_t index;
uint8_t buttonPin;
tPressedState pressedState;
tPressedState oldPressedState;
uint32_t lastStateChange;
} tButton;
tButton buttons[] = {
{ 1, SWITCH_1, psHIGH, psINVALID, 0 },
{ 2, SWITCH_2, psHIGH, psINVALID, 0 },
{ 3, SWITCH_3, psHIGH, psINVALID, 0 },
{ 0, 0, psINVALID, psINVALID, 0 } // END MARKER
};
static void buttonHandler(tButton *button) {
uint32_t currentMicros = micros();
uint8_t buttonState = digitalRead(button-&gt;buttonPin);
#ifdef DEBUG
if (button-&gt;oldPressedState != button-&gt;pressedState) {
Serial.print("Index ");
Serial.print(button-&gt;index);
Serial.print(", state changed from ");
Serial.print(button-&gt;oldPressedState);
Serial.print(" to ");
Serial.print(button-&gt;pressedState);
Serial.println();
button-&gt;oldPressedState = button-&gt;pressedState;
}
#endif
switch (button-&gt;pressedState) {
case psHIGH:
if (buttonState == LOW) {
button-&gt;pressedState = psLOW;
button-&gt;lastStateChange = currentMicros;
}
break;
case psLOW:
if (buttonState == HIGH) {
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
} else {
if (currentMicros &gt; (button-&gt;lastStateChange + configBlock.debounce)) {
button-&gt;pressedState = psACCEPTED_LOW;
button-&gt;lastStateChange = currentMicros;
}
}
break;
case psACCEPTED_LOW:
if (buttonState == HIGH) {
button-&gt;pressedState = psSHORT;
button-&gt;lastStateChange = currentMicros;
}
if (currentMicros &gt; (button-&gt;lastStateChange + (configBlock.longPress * 1000))) {
button-&gt;pressedState = psLONG_START;
button-&gt;lastStateChange = currentMicros;
}
break;
case psSHORT:
sendMsg(button-&gt;index, "PRESS_SHORT");
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_START:
sendMsg(button-&gt;index, "PRESS_LONG_START");
button-&gt;pressedState = psLONG_CONT;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_CONT:
if (buttonState == HIGH) {
button-&gt;pressedState = psLONG_END;
button-&gt;lastStateChange = currentMicros;
}
if (currentMicros &gt; (button-&gt;lastStateChange + (configBlock.longPressRepeat * 1000))) {
button-&gt;pressedState = psLONG_CONT_SEND;
button-&gt;lastStateChange = currentMicros;
}
break;
case psLONG_CONT_SEND:
sendMsg(button-&gt;index, "PRESS_LONG_CONT");
button-&gt;pressedState = psLONG_CONT;
button-&gt;lastStateChange = currentMicros;
break;
case psLONG_END:
sendMsg(button-&gt;index, "PRESS_LONG_END");
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
break;
default:
button-&gt;pressedState = psHIGH;
button-&gt;lastStateChange = currentMicros;
}
}
```

View File

@ -0,0 +1,8 @@
<!--
title: How to add a CA certificate in Debian
-->
Copy CA file with extension `crt` into `/usr/local/share/ca-certificates/`.
Call `update-ca-certificates` as root.

View File

@ -0,0 +1,34 @@
<!--
title: Colors in Minicom
-->
To start `minicom` in color mode use
```
minicom -c on
```
Switch terminal emulation to ANSI.
Use escape sequences to actually change the color of text as described for instance here
https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html.
The base sequence is `\1b[Xm` where X is a number as described below.
To get the colors in bright style, use the sequence `\x1b[X;1m`.
Number | Color
----|----
0 | reset
1 | highlight
7 | inverse
30 | black
31 | red
32 | green
33 | yellow
34 | blue
35 | magenta
36 | cyan
37 | white

View File

@ -0,0 +1,58 @@
<!--
title: Children Protection for Postfix-based EMail-Server
date: 2013-06-27
-->
This small tool implements a whitelist on a Postfix mail-server. It prevents certain recipient addresses (your kids ones) from
receiving mail from any not whitelisted address. Any mail from not whitelisted senders is redirected to a delegate (a parent).
The code for this tool can is here: [https://gitea.hottis.de/wn/childprot](https://gitea.hottis.de/wn/childprot).
Configure the tool by adding this line into the `master.cf` of the Postfix installation:
```
childprot unix - n n - 25 spawn user=mail argv=/opt/sbin/ChildProt
```
and this one to the `main.cf`:
```
check_policy_service unix:private/childprot
```
The restricted recipients and the whitelists are stored in an SQLite3 database:
```
CREATE TABLE child_address_t (
child INTEGER REFERENCES child_t(id),
address TEXT
);
CREATE TABLE child_t (
id INTEGER PRIMARY KEY,
name TEXT,
delegate TEXT
);
CREATE TABLE whitelist_t (
child INTEGER REFERENCES child_t(id),
address TEXT
);
CREATE VIEW child_v AS
SELECT c.id as id,
c.delegate as delegate,
ca.address as address
FROM child_t c,
child_address_t ca
WHERE c.id = ca.child;
```
Restricted persons together with their delegates are added to the table `child_t`, multiple addresses can be assigned to those persons in
`child_address_t`. Whitelists per person are maintained in `whitelist_t`.
The tool is querying the view `child_v`.
**Note: The code is unmaintained and here only for documentary reasons. It is not meant to be used any longer.**

View File

@ -0,0 +1,18 @@
<!--
title: Engel des Herrn
-->
Der Engel des Herrn brachte Maria die Botschaft, und sie empfing vom Heiligen Geist.
Gegrüßet seist du, Maria …
Maria sprach: Siehe, ich bin die Magd des Herrn; mir geschehe nach deinem Wort.
Gegrüßet seist du, Maria …
Und das Wort ist Fleisch geworden und hat unter uns gewohnt.
Gegrüßet seist du, Maria …
Bitte für uns, heilige Gottesmutter (heilige Gottesgebärerin), (auf) dass wir würdig werden der Verheißungen Christi.
Lasset uns beten. Allmächtiger Gott, gieße deine Gnade in unsere Herzen ein. Durch die Botschaft des Engels haben wir die Menschwerdung Christi, deines Sohnes, erkannt. Führe uns durch sein Leiden und Kreuz zur Herrlichkeit der Auferstehung. Darum bitten wir durch Christus, unsern Herrn. Amen.

View File

@ -0,0 +1,61 @@
<!--
title: Gitlab Backup and Restore
-->
## Backup
Find the backup directory:
```
grep backup_path /etc/gitlab/gitlab.rb
```
Issue backup:
```
sudo gitlab-backup create
```
Transfer backup using scp to destination machine.
Backup configuration and secrets:
```
sudp cp /etc/gitlab/gitlab-secrets.json /backuppath/
sudo cp /etc/gitlab/gitlab.rb /backuppath/
```
## Restore
See also here: [https://docs.gitlab.com/ee/administration/backup_restore/restore_gitlab.html](https://docs.gitlab.com/ee/administration/backup_restore/restore_gitlab.html)
*DO NOT OVERWRITE THE CONFIGURATION ON THE DESTINATION MACHINE. COMPARE IT AND CONSIDER AND EVALUATE EACH DIFFERENCE*
Stop processes of GitLab connecting to the database:
```
gitlab-ctl stop puma
gitlab-ctl stop sidekiq
# check
gitlab-ctl status
```
Do not stop the whole system since the restore tool has to connect to the database which would also stop in that case.
Issue restore. Run this command in a screen session. It is running quite long and requires manual intervention in between.
```
sudo gitlab-backup restore BACKUP=...
```
Use the datecode and the version tag of the backup created above.
Remember secrets and configuration. Do not overwrite configuration, see above.
Reconfigure the instance:
```
sudo gitlab-ctl reconfigure
```
Start the instance:
```
sudo gitlab-ctl start
```

View File

@ -0,0 +1,27 @@
<!--
title: Gitlab Change BaseURL in Database
-->
## Change URL
After a migration changing the base url in the configuration is not enough. It must also be changed in the database.
* Adjust the variable `external_url` in the file `/etc/gitlab/gitlab.rb` and run `gitlab-ctl reconfigure`
* Adjust the canonical URL in the database:
```
gitlab-rails console
ApplicationSetting.current.update!(home_page_url: 'https://neue-url.example.com')
ApplicationSetting.current.update!(after_sign_out_path: 'https://neue-url.example.com')
```
* Reading out a value from the ApplicationSetting via the gitlab-rails console is done using
```
ApplicationSetting.current.home_page_url
```
* Clear the internal cache:
```
gitlab-rake cache:clear
```

View File

@ -0,0 +1,24 @@
<!--
title: Gitlab Upgrades
-->
## Upgrade of a GitLab instance
When upgrading a Gitlab instance, strictly follow the defined upgrade path. Consider to snapshot the filesystem if possible after each step.
Additional, after each step wait until all background migrations are completed before performing the next upgrade step.
* [Upgrade Paths](https://docs.gitlab.com/ee/update/index.html#upgrade-paths)
* [Upgrading to a specific version](https://docs.gitlab.com/ee/update/package/#upgrade-to-a-specific-version-using-the-official-repositories)
To find the versions of a specific package in the Debian apt cache use
```
apt-cache madison gitlab-ce
```
To upgrade to a specific version use
```
apt install gitlab-ce=<version>
```
**Definitely observe the version specific upgrade instructions, especially background migrations!**

View File

@ -0,0 +1,63 @@
<!--
title: iSCSI on Linux
-->
## Preparation
Install `open-iscsi`, at least on Debian systems.
## Use an iSCSI target from Linux
In our setup a Synology NAS at 172.16.200.19 provides the targets.
First, run
```
iscsiadm -m discovery -t sendtargets -p 172.16.200.19
```
to discover all provided targets.
You get something like this
```
172.16.200.19:3260,1 iqn.2000-01.com.synology:nas.Target-GitLab.db1c0541e7
[fe80::211:32ff:febe:da31]:3260,1 iqn.2000-01.com.synology:nas.Target-GitLab.db1c0541e7
172.16.200.19:3260,1 iqn.2000-01.com.synology:nas.Target-Bitwarden.db1c0541e7
[fe80::211:32ff:febe:da31]:3260,1 iqn.2000-01.com.synology:nas.Target-Bitwarden.db1c0541e7
172.16.200.19:3260,1 iqn.2000-01.com.synology:nas.Target-Nextcloud.db1c0541e7
[fe80::211:32ff:febe:da31]:3260,1 iqn.2000-01.com.synology:nas.Target-Nextcloud.db1c0541e7
172.16.200.19:3260,1 iqn.2000-01.com.synology:nas.Target-MariaDB.db1c0541e7
[fe80::211:32ff:febe:da31]:3260,1 iqn.2000-01.com.synology:nas.Target-MariaDB.db1c0541e7
172.16.200.19:3260,1 iqn.2000-01.com.synology:nas.Target-Backup.db1c0541e7
[fe80::211:32ff:febe:da31]:3260,1 iqn.2000-01.com.synology:nas.Target-Backup.db1c0541e7
```
Now, connect to the target using
```
iscsiadm -m node --targetname "iqn.2000-01.com.synology:nas.Target-Backup.db1c0541e7" \
--portal 172.16.200.19 --login
```
A new SCSI device will be created. Check the name of the device using ''dmesg''. You see something like this
```
[16924536.979916] scsi host13: iSCSI Initiator over TCP/IP
[16924537.010635] scsi 13:0:0:1: Direct-Access SYNOLOGY iSCSI Storage 4.0 PQ: 0 ANSI: 5
[16924537.011449] sd 13:0:0:1: Attached scsi generic sg10 type 0
[16924537.012597] sd 13:0:0:1: [sdj] 209715200 512-byte logical blocks: (107 GB/100 GiB)
[16924537.012827] sd 13:0:0:1: [sdj] Write Protect is off
[16924537.012828] sd 13:0:0:1: [sdj] Mode Sense: 43 00 10 08
[16924537.013111] sd 13:0:0:1: [sdj] Write cache: enabled, read cache: enabled, supports DPO and FUA
[16924537.013361] sd 13:0:0:1: [sdj] Optimal transfer size 16384 logical blocks > dev_max (8192 logical blocks)
[16924537.018630] sd 13:0:0:1: [sdj] Attached SCSI disk
```
Now use `fdisk`, `mkfs` and if you like `blkid` on the new device and put it into the `/etc/fstab`.
===== Authenticated target =====
```
iscsiadm --mode node --targetname "iqn.2007-01.org.debian.foobar:CDs" -p 192.168.0.1:3260 --op=update --name node.session.auth.authmethod --value=CHAP
iscsiadm --mode node --targetname "iqn.2007-01.org.debian.foobar:CDs" -p 192.168.0.1:3260 --op=update --name node.session.auth.username --value=$Id
iscsiadm --mode node --targetname "iqn.2007-01.org.debian.foobar:CDs" -p 192.168.0.1:3260 --op=update --name node.session.auth.password --value=$MDP
iscsiadm --mode node --targetname "iqn.2007-01.org.debian.foobar:CDs" -p 192.168.0.1:3260 --login
```

View File

@ -0,0 +1,44 @@
<!--
title: Magnifikat
-->
Bibellese zum 15.12.2013
1,46 Und Maria sprach:
Meine Seele erhebt den Herrn,
47 und mein Geist freut sich Gottes, meines Heilandes;
48 denn er hat die Niedrigkeit seiner Magd angesehen.
Siehe, von nun an werden mich selig preisen alle Kindeskinder.
49 Denn er hat große Dinge an mir getan,
der da mächtig ist und dessen Name heilig ist.
50 Und seine Barmherzigkeit währt von Geschlecht zu Geschlecht
bei denen, die ihn fürchten.
51 Er übt Gewalt mit seinem Arm
und zerstreut, die hoffärtig sind in ihres Herzens Sinn.
52 Er stößt die Gewaltigen vom Thron
und erhebt die Niedrigen.
53 Die Hungrigen füllt er mit Gütern
und lässt die Reichen leer ausgehen.
54 Er gedenkt der Barmherzigkeit
und hilft seinem Diener Israel auf,
55 wie er geredet hat zu unsern Vätern,
Abraham und seinen Kindern in Ewigkeit.
Lukas 1,46-55
http://m.die-bibel.de/luther-bibel-1984/bibelstelle/Lukas%201?utm_source=Bibellese_Apple&utm_medium=App&utm_campaign=Bibellese

View File

@ -0,0 +1,37 @@
<!--
title: Neovim Setup
-->
Lots of information on nvim can be found for instance here:
* https://programmingpercy.tech/blog/learn-how-to-use-neovim-as-ide/
* https://github.com/hrsh7th/
* https://github.com/wbthomason/packer.nvim
* https://docs.rockylinux.org/books/nvchad/nvchad_ui/nvimtree/
## Installation of Neovim
On Debian install neovim from the sources, the packages are mostly a bit aged.
```shell
git clone https://github.com/neovim/neovim
sudo apt install ninja-build gettext cmake unzip curl
make CMAKE_BUILD_TYPE=Release
sudo make install
```
On Windows install from binary or using installer, on MacOS use `brew`.
Debian packages can be found here: https://github.com/neovim/neovim-releases/releases
## Configuration
Clone the packer repository:
```shell
git clone --depth 1 https://github.com/wbthomason/packer.nvim ~/.local/share/nvim/site/pack/packer/start/packer.nvim
```
Clone the local configuration repo:
```shell
git clone git@gitea.hottis.de:wn/my-nvim-config.git ~/.config/nvim
```
At the first start of nvim a lot of error messages will be shown. Ignore them and run `:PackerInstall`. At the next start everything should be fine.
The file `~/.config/nvim/init.lua` contains both plugins to be loaded and regular settings for nvim. The directory `~/.config/nvim/lua` contains configuration for individual plugins.

View File

@ -0,0 +1,19 @@
<!--
title: Execute occ in Nextcloud pod
-->
First, look up the name of the pod using
```
kubectl get pods -n nextcloud
```
Then, get into the pod using
```
kubectl exec --stdin --tty NAME_OF_THE_POD -c nextcloud -n nextcloud -- sh
```
Finally, within the pod
```
su -s /bin/sh www-data -c "php occ --help"
```

View File

@ -0,0 +1,168 @@
<!--
title: Solution for Prince of Persia 1
-->
# Lösung Prince of Persia 1
## Komplettlösung zu "Prince of Persia 1"
Zuallererst mal zur Joysticksteuerung: Wenn Ihr beim
Springen den Feuerknopf gedrückt haltet, macht der Prince
einen 'Klammersprung', d.h., bei grossen Entfernungen
springt er an die gegenüberliegende Wand und klammert sich
dort fest. Mit dem Joystick dann einfach nach oben drücken
und schon ist's geschafft.
Ausserdem kann man teilweise Decken aufstossen (VORSICHT,
wenn die Platten dann runterfallen!); aber dies ist für das
Spiel nur dann nötig, wenn man in einer Sackgasse steckt
und der Weg über die Decke weitergeht. Ansonsten sind dort
meist 'nur' Potions versteckt. ACHTUNG: Um das Spiel
zeitlich zu schaffen empfiehlt es sich, (wenn nicht
wirklich nötig) die Deckengänge NICHT zu benutzen. Das
Spiel an sich verfügt über 13 Level (12 Level + den
Abschlußlevel mit Kampf gegen Jaffar). Wenn man alle Level
kennt und perfekt spielt (nie kaputt geht) braucht man
trotzdem ca. 45-50 min. Um das Spiel also zu schaffen, muß
man in allen Leveln den Weg kennen. Da dies natürlich nicht
beim erstenmal klappt ist klar; also immer ein bis zwei
Level weiterarbeiten und gut auskundschaften.
Das Ziel je Level ist simpel:
- Türe zum nächsten Level finden
- Türe zum nächsten Level öffnen
- JEDE Superpotion finden und trinken!!!
## Die einzelnen Level:
### Level 1:
Hier holt Ihr Euch das Schwert
### Level 2:
Nix besonderes, allerdings muss man am Ende zum ersten Mal
den Klammersprung ausführen.
### Level 3:
Dieser Level ist in 2 Teile unterteilt:
- Klettert soweit nach oben, wie Ihr könnt, dann einen
Sprung in die nicht sichtbare rechte Seite, dort den
Türmechanismus betätigen und SCHNELL solange nach links
laufen, bis Ihr das sich schließende Tor seht; sofort (aus
dem Lauf) einen Klammersprung machen.
- Türmechanismus finden und Tür öffnen. Beim Zurücklaufen
vorsichtig an das Skelett ranschleichen, es im Kampf die
Schlucht runterstoßen, ihm nachklettern und es nochmal
besiegen.
### Level 4:
Superpotion holen, Türmechanismus betätigen, und durch
Spiegel mit Anlauf springen --> Shadow wird geboren (er
wird Euch noch einigen Ärger bereiten)
### Level 5:
Beim Versuch die Superpotion zu holen, stiehlt sie Euch
Shadow. Ihr müßt aber den Versuch trotzdem ausführen!
(Erklärung später)
### Level 6:
(Sehr kurzer Level) Kämpft mit dem dicken Wächter, indem
Ihr auch abwehrt (dazu müßt Ihr den Joystick nach oben
drücken). Der Sprung zu Shadow mißlingt und Ihr werdet in
Level 7 FALLEN.
### Level 7:
Holt Euch die Superpotion (,die man schon am Anfang sieht)
und springt dann in die Schlucht hinein, denn die Potion
besitzt die magischen Kräfte, Euch fliegen zu lassen.
### Level 8:
Den ersten Wächter schafft man leicht mit der
Joystickkombination: VOR, HOCH, 2x Feuerknopf (solange
wiederholen, bis er tot ist) Wenn Ihr ganz rechts im Level
angekommen seit und Euch auf den Weg macht, links den
Türmechanismus zu betätigen sind einige Fallen:
- Der erste Wächter oben ist nur zu schaffen, wenn Ihr
schon im vorigen Bild losspringt (er kann dann nicht
schnell genug reagieren, trotzdem bekommt Ihr einen Schlag
ab!)
- Nun müsst Ihr schnell sein (aber immer ruhig und nicht
überhasten), da mit dem Türmechanismus 3 (!) Tore auf und
zu gehen, also fix durch die Fallmesser.
- Wenn Ihr den Türmechanismus betätigt habt und plötzlich
nicht mehr nach rechts weiterkommt, müßt Ihr auf eine Maus
warten, die den Türmechanismus betätigt (Ahhh!!)
### Level 9:
Einfach durchspielen, aber AUFPASSEN: Die erste Superpotion
nicht trinken, da sonst der Bildschirm auf dem Kopf steht!
Die zweite Superpotion (im Bild nebenan) ist wieder ok und
die dritte kehrt den Bildschirm wieder um, falls Ihr die
erste getrunken habt. Noch ein Tip: Wenn Ihr das Tor zu
Level 10 gefunden habt seht Ihr zwei Säulen; AUF der
rechten befindet sich der Mechanismus, der die Tür zur
linken Säule öffnet. Ihr MÜSST diesen Mechanismus
betätigen.
### Level 10:
Zuerst die Wache ganz links töten, dann rechts durch die
zwei Fallmesser (2x) hüpfen. Im nächsten Bild den Wächter
NICHT fertigmachen, stattdessen oben die Decke einstoßen,
hochklettern und von dort OHNE PAUSE nach rechts laufen.
### Level 11:
Stoßt im zweiten Bild neben der Säule die Decke auf,
klettert hoch und lauft dann OHNE Pause nach rechts zur
Superpotion. Vor dem ersten Fallbeil die Decke aufstoßen
hochklettern und ganz nach links (ohne Pause) laufen. Wenn
Ihr den nächsten Wächter fertiggemacht habt, springt Ihr
aus dem Lauf nach rechts und klammert 2x.
### Level 12:
Ziemlich tricky! Nach oben klettern, bis ein Weg nach links
führt. Diesen ohne Pause durchlaufen und am Ende nach links
springen. Hochklettern bis Ihr eine Möglichkeit seht nach
rechts zu springen. Hier muss man dann ziemlich schnell 3x
nach rechts springen. Es geht dann so ähnlich weiter, bis
man auf dem mittleren Turm ganz oben steht. Dort stoßt Ihr
die Decke auf, klettert hoch, lauft auf der Plattform ganz
nach rechts (Achtung das letzte Teil ist wieder lose),
springt dann AUS DEM LAUF nach links und rennt bis zur
Wand. Wenn Ihr nun hochklettert, bemerkt Ihr, daß das
Schwert fehlt. Ihr geht vorsichtig aber zügig über die 2
Fallteile und bleibt dann SOFORT stehen. Shadow springt nun
mit gezückter Waffe auf Euch zu. Nun AUF KEINEN FALL mit
ihm kämpfen und stattdessen SOFORT Euer Schwert einstecken
(Joystick nach unten). Nach der Vereinigung lauft Ihr
einfach nach links weiter (nicht wundern, probierts einfach
aus, Ihr fallt schon nicht!)
### Level 13:
Abwarten bis alles von den Decken gefallen ist, und erst
dann los laufen. Jaffar erledigt Ihr am besten, wenn Ihr
über das Fallteil auf ihn zu hüpft. Der Kampf ist nicht
einfach, da Jaffar über 4! Schlagkombinationen verfügt.
Noch einmal VORSICHT. Wenn Ihr ihn besiegt habt lauft Ihr
nach rechts, dann wieder nach links (das Tor geht auf),
wenn Ihr nun in Richtung Tor nach links geht, springt am
besten in das Bild, in dem das Tor ist, da Ihr sonst
womöglich in die Schlucht fallt und nochmal kämpfen müsst.
Der Rest ist geschenkt und Ihr betretet als Prince of
Persia die Hall of fame!!
Diese Lösung stammt aus Mogel-Power (www.mogelpower.de) / Solution.Net (solution.mogelpower.de)

View File

@ -0,0 +1,13 @@
<!--
title: PuTTY and OPENGPG hardware keys
-->
* install gpg4win installed
* create or edit the file `gpg-agent.conf`, usually in `c:\Users\XXX\AppData\Roaming\gnupg\`:
```
enable-putty-support
enable-ssh-support
use-standard-socket
```

View File

@ -0,0 +1,14 @@
<!--
title: Resize HDD on running system
-->
* Resize target on VMWare or on Synology or where ever it is provided
* Stop services using the disk
* Unmount the disk
* Run `e2fsck -f` on the disk
* Rescan disks using `echo 1>/sys/class/block/sdx/device/rescan` (replace `sdx` by actual disk device)
* Extend partition using `resize` in `cfdisk`
* Extend filesystem using `resize2fs` on extended partition
* Mount the partition
* Start services

View File

@ -0,0 +1,136 @@
<!--
title: PL 9823 meets MSP430
date: 2024-05-25
-->
## Generating signals for PL 9823 using a MSP430
### Debugging
```
mspdebug rf2500 gdb
msp430-gdb -x firmware.gdb
```
Attention: the gdb in the TI toolchain package is broken, use the one from Debian
### Signals Working Cycler
These signals are related to code under tag `cycler_works_include_output_stage`.
First octets:
![](/static/cycler_working_first_octets.png)
Last octets:
![](/static/cycler_working_last_octets.png)
Schematics and legend for signals:
![](/static/schematics.jpeg)
#### Some more explanations
Consider above schematics and the screen shot "Last octets" from the oscilloscope.
![](/static/timing.png)
Timer TA1 is running in "up mode" to the value 45 set in compare register `TA1CCR0`. The compare registers `TA1CCR1` is set to 10, `TA1CCR2` is set to 22.
The output mode of the timer is set to "Reset/Set", which means the GPIO associated with `TA1CCR1` (P2.1) and `TA1CCR2` (P2.4) are set at the overflow and
restart of the counter and reset when the counter matches the associated compare value.
So, on P2.1 (D1 on the oscilloscope) we have a long pulse and at P2.4 (D0 on the oscilloscope) we have a short pulse, with synchronous raising edge.
![](/static/74hc74-function-table.png)
The inverted signal P2.4 is connected to the Clock input of a 74HC74 D-flipflop, the data input of the flipflop is connected to GPIO P1.0 (D2 on the oscilloscope).
The interrupt service routine `shifter_isr` is triggered by the overflow and restart of the timer, this interrupt service routine provides the next bit to be
signaled on P1.0. This bit is stored at the falling edge of P2.4 (long pulse) in the flipflop.
The short pulse (P2.1, D1) is ANDed using a 74HC08 with the inverted output of the flipflop, the long pulse (P2.4, D0) is ANDed with the non-inverted output of
the flipflop, the ANDed results are ORed using a 74HC32.
So, at the output of the OR gate (yellow on the oscilloscope) we get a long pulse for a 1 at P1.0 provided by the ISR and a short pulse for a 0 at P1.0.
The routine `drawscreen` takes color values from the "frame buffer" beginning at `screendata` and translated them into the red, green and blue values and provides these values, first red, then green and finally blue to the ISR via the `DATA_REGISTER`.
The ISR cycles over the `DATA_REGISTER` and presents the bits at P1.0.
Additionally, when the first bit of a full draw screen cycle is presented at P1.0 by the ISR, it also sets the data enable signal at P1.1 and when the last bit has been provided it disabled the data enable signal. This signal is also synchronized using a flipflop and used to enable the short/long pulses using an AND gate.
### Timing
Complete cycle: 2.48us
![](/static/pulse_complete.png)
Short pulse: 550ns
![](/static/pulse_short.png)
Long pulse: 1.18us
![](/static/pulse_long.png)
### Load Time
During of loading data into five LEDs: 297us
![](/static/five_leds.png)
During of loading data into six LEDs: 297us
![](/static/six_leds.png)
| # of LEDs | Load Time measured | calculated |
| --------- | ------------------ | ---------- |
| 5 | 297us | |
| 6 | 354us | 356.4us |
| 10 | | 594us |
| 100 | | 5.9ms |
| 200 | | 11.8ms |
### Reset Circuitry
It appears that the output voltage of the power supply raises that slow, that the MCU
will not handle the reset correctly.
The following circuitry should generate a valid reset signal far enough from the raise
of the supply voltage:
![](/static/reset-circuit.jpeg)
The circuit generates the following signals:
![](/static/reset-signal.png)
##### Reference voltage (green):
```math
U_ref = 3.3V \frac{22k\Omega}{22k\Omega + 10k\Omega} = 2.2V
```
##### Trigger voltage (purple):
```math
U_trigg = 3.3V \frac{330k\Omega}{330k\Omega + 82k\Omega} = 2.64V
```
##### RC constant:
```math
\tau = 82k\Omega \cdot 100nF = 8.2ms
```

View File

@ -0,0 +1,12 @@
<!--
title: snmpwalk with numeric and text output of oid
-->
```
snmpwalk -v 2c -c $COMMUNITY -On $HOST $BASE_OID | while read -r line; do
oid=`echo $line | awk '{print $1}'`
textoid=`snmptranslate $oid`
value=`echo $line | cut -d ' ' -f 3-`
echo "$oid ($textoid): $value"
done
```

View File

@ -0,0 +1,75 @@
<!--
title: Tetris
date: 2024-05-27
-->
# Tetris - Hardware and Software
![](/static/IMG_4936.jpg)
Update Amplifier (separate input circuitry per PSG, it appears, that a silent PSG has a DC level on its output which is summarized to the AC output of the working PSG, so two input circuits with individual couping capacitor):
![](/static/IMG_4941.jpg)
Update of the power switch of the amplifier (at appears, that the small transistor couldn't deliver enough current):
![](/static/IMG_4958.jpeg)
This Tetris implementation consists of a hardware and a software (running on that hardware).
The hardware utilizes four MSP430 microcontrollers for 1.) the game play, 2.) the play ground canvas, 3.) the score display and 4.) the sound effects.
Further documentation including calculations and drawing can be found in the `docs` subdirs of the four main subdirs.
## Game Play
Code is in subdir `game-ctrl` (https://gitea.hottis.de/wn/tetris/src/branch/main/game-ctrl).
In the firmware for this MSP430 microcontroller the whole game mechanics, reading the buttons, reading and writing the highscore EEPROM and the control of the peripherial microcontrollers are implemented.
The buttons are debounced using RC circuitry and Schmitt triggers and connected to GPIOs of the microcontroller.
The peripherial microcontrollers and the EEPROM are connected via SPI including individual chip select lines.
![](/static/game-ctrl.jpg)
## Play Ground Canvas
Code is in subdir `rgb-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/rgb-driver).
The play ground is implemented using a 10 * 20 matrix of PL9823 RGB LEDs which are controlled by another MSP430 microcontroller. The firmware for this microcontroller is implemented for performance and real time requirements in assembly code. Through some discret logic the signals for PL9823 LEDs are generated. Major challenge was to generated the signals according the datasheet of all 200 (including a mini canvas for the stone preview: 212) LEDs in real time without interrupts.
The communcation with the game play controller is implemented as a sequences of tuples of LED address (0 to 211) and color code. A single octet of 253 where the LED address is expected is taken as the end-of-telegram mark. Readiness to receive a telegram is signaled to the game play controller via a single line connected to a GPIO of the game play controller.
![](/static/rgb-driver.jpg)
[Details are here]({{< ref "rgb-driver.md" >}} "Details are here")
## Score Display
Code is in subdir `display-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/display-driver).
In the first place, a MAX7221 was meant to be used for connecting a multiple digit seven-segment display. However, it appears, that the MAX7221 requires 3.5V as minimum voltage for the high-level, which caan't be provided by the MSP430 (which runs on 3.3V) and level-shifters haven't been around. Thus, the minimal required amount of functionality of the MAX7221 has been implemented in C on an MSP430. Just four digits are supported.
Communication with the game play controller is just a 16 bit number to be displayed.
![](/static/display-driver.jpg)
## Sound Effects
Code is in subdir `sound-driver` (https://gitea.hottis.de/wn/tetris/src/branch/main/sound-driver).
An MSP430 microcontroller and two mediaeval AY-3-8913 sound chips are deployed. The sound chips themselve run on 5V, their 8-bit-address/data bus is connected to the port 2 (bit 0 to 7) of the microcontroller. The bus control signal `_CS`, `BC1` and `BDIR` are generated in software and provided via GPIOs.
An amplifier following the proposal of the AY-3-8913 datasheet is implemented using a LM386 chip. A MOSFET BS108 controlled via a GPIO is use the shortcut the input of the amplifier to ground to mute sound effects.
The clock generator proposed by the AY-3-8913 does not work reliably, so an alternative design from "The Art of Electronics" has been used.
![](/static/sound-driver-1.jpg)
![](/static/sound-driver-2.png)
![](/static/sound-driver-3.jpg)
![](/static/sound-driver-4.jpg)

View File

@ -0,0 +1,67 @@
<!--
title: Theremin
date: 2013-07-01
-->
A [Theremin](https://en.wikipedia.org/wiki/Theremin) is a rather old electronic music instrument, invented in 1928. It is played by approaching hands to two antennas, without touching them. One antenna is used to manipulate the frequeny of the tone, the other one to manipulate the volume.
![](/static/foto-am-30-06-13-um-20-021.jpg)
This is just another Theremin. Only basic structure of the circuit was taken from many other published Theremin circuits.
![](/static/scan_005006-1024x654.jpg)
Completely new (or at least not found during my Theremin googling) is the digital zero-calibration.
The both left-hand-side oscillators together with the mixer+filter block provide the signal to control the volume, the right-hand-side oscillators and mixer+filter block provide the signal to control the frequency.
Each of these both couples consists of two oscillators and a mixer+filter block. Both oscillators have to swing on exactly the same frequency, in this case of about 1.3MHz. While the exact frequency does not matter, it is significant that both oscillators have the same frequency. The signals of both oscillators will be mixed, which means, multiplied.
$$\sin(\omega_0 t) sin(\omega t)$$
Here $\omega$ is the frequncy of one of the oscillators while $\omega_0$ is the frequency of the other one.
This term can be modified using the addition rule for trigonometric functions into
$$\frac{\cos((\omega_0-\omega)t)-\cos((\omega_0+\omega)t)}{2}$$
Due to this transformation, two signals, one with the sum and one with the difference of both input signal frequencies, are accumulated.
When both frequencies are exactly the same, one part of the sum appears as a DC offset, while the other part is the doubled frequency.
If one oscillator is de-tuned by only a few Hz'`s, one part are this few Hz'`s (a very low, hearable frequency) and the other part is still (roughly) the doubled frequency (a high frequency). The high frequency part can now be suppressed using a lowpass-filter.
Multiplication of two signals can be done using an analog four quadrant multiplier, like the AD633. So, this is the schematic of the mixer+filter block:
![](/static/scan_005006_5-1024x717.jpg)
The output signal of this block is the difference of the detuning of the one oscillator.
Detuning of the oscillator will be achieved by approaching the hand to the antenna of the oscillator.
![](/static/scan_005006_3.jpg)
The antenna acts as a kind of a capacitive sensor and by approaching the hand a very small amount of capacity is added into the LC resonator.
The other oscillator is a fix-frequency oscillator which can be tuned to swing on the same frequency as the first oscillator in a not detuned state.
![](/static/scan_005006_4.jpg)
This tuning is achieved by biasing the two varactor diodes.
Here is automated tuning circuit steps in:
![](/static/scan_005006_6.jpg)
The low-frequency output signal of the mixer+filter block is provided through a 2-to-1 multiplexer (the four NAND-gates) into a microcontroller. The microcontroller measures the frequency and as long as it is above a frequency $\epsilon$ of say 10Hz, the bias voltage $U_{tune}$ is increased.
These both oscillators with mixer+filter and one channel of the zero-calibration appear twice in the whole circuit, one for frequency manipulation and one for volume manipulation.
The low-frequency, hearable, signal and the volume-control signal are brought together in the volume-control circuit
![](/static/scan_005006_2-1024x553.jpg)
Here, the low-frequency signal $U_{Lf1}$ is passed through a high-pass filter. The high-pass filter is calculated that way that the whole detunable frequency range comes onto the ramp of the filter. So, the not detuned output signal of the mixer+filter is a DC signal, which is suppressed completely by the high-pass filter (beginning of the ramp) and the maximum detuned output signal of about 2kHz matched roughly to the end of the ramp. This filtered signal is rectified and only the negative half-wave of the signal passes the diode. This half-wave signal is sieved by the larger capacitor to get a DC signal between 0 and the maximum amplitude which passed the fiter. This negative DC signal is fed into the FET, which is configured as a voltage controlled resistor. This voltage controlled resistor and the fix resistor (5k6) are building a voltage controlled voltage divider. The hearable frequency signal $U_{Lf2}$ is fed into this voltage divider  and passed to an amplifier.
The output signal of this block in turn is the volume-controlled and frequency-controlled signal which is the output signal of this Theremin. It is passed into a power-amplifier and into a speaker - done.
[Calibrating the Theremin](https://www.youtube.com/watch?v=5US8LY_FbQ4&amp;w=420&amp;h=315)
[Playing the Theremin](https://www.youtube.com/watch?v=lDld71HI66o&amp;w=420&amp;h=315)

View File

@ -0,0 +1,25 @@
<!--
title: Three Phase Inverter - Second Service
date: 2016-12-19
-->
I wrote in October about my first try to build a simple three phase inverter, see [here]({{< ref "three-phase-inverter.md" >}}). In the first try I used four MSP430 microcontroller, one for the PWM of each phase and one to coordinate the phase shift of the three phases.
In this experiment I put everything on one STM32 microcontroller. Here I used the DMA feature to feed data into the PWM counter and I calculated the sine values at start-up time on the microcontroller. Additionally I put in the driver for a CAN interface, however, it is not yet supported in the firmware.
![](/static/img_0140.jpg)
From top to bottom you see the CAN driver, the STM32 board, opto coupler to separate logic and power part and then from right to left in the bottom half the low-side/high-side MOSFET drivers and the MOSFETs.
![](/static/img_0144.jpg)
The power supply consists of a traditional transformer and (top right) the rectifier and capacitors for the power part, together with the 12V regulator for the drivers and (top left) the regulators for 3.3V and 5V for the logic part.
![](/static/img_0146.jpg)
The motor is the same as in the earlier experiment - I don't have too much of them. And everything is put onto one board:
![](/static/img_0143-e1482141676335.jpg)
The code for this experiment is here: [https://gitea.hottis.de/wn/inverter2](https://gitea.hottis.de/wn/inverter2).

View File

@ -0,0 +1,44 @@
<!--
title: Three Phase Inverter
date: 2016-10-14
-->
Already when I was still in school, about 30 years ago, I was curious to make an inverter using some MOSFETs. I actually was able to build a simple one phase inverter with rectangular signal shape (I used a NE555). Using this thing I drove a transformer to light a blub. However, all of these inverters I built passed by in fire.
Now, I tried it again, not longer using MOSFETs but IGBTs with free-wheeling diode. Moreover, I used some microcontrollers and sine values to feed a PWM to get a sine-alike signal shape. And this time I was able with three phases to drive an asynchronous motor.
![](/static/img_0053.jpg)
The signal shaping is done with four MSP430 controllers, three as PWMs to drive the bridge and one to coordinate and control the three PWMs. The PWM controller is decoupled from the IGBT driver (IR2184) using optic couplers.
![](/static/img_0054-e1476437702547.jpg)
The bridge is a three phase IGBT module is a 6MB120F-060 I got for a few euros at ebay.
![](/static/img_0055-e1476437685461.jpg)
To avoid high voltages in my setup I got a 24V async motor, also from ebay.
![](/static/img_0056.jpg)
The PWMs generate the signal from a sine table generated using Excel. Those I got this signal:
![](/static/inverter0_2016-09-23-4.png)
The main task of the coordinator is the start the PWMs with a phase shift of 120° (digital line 1, 2 and 3):
![](/static/2016-10-13_1.png)
Currently the PWMs start with random polarity. The interesting signals are the digital lines 4, 5 and 6.
Sometimes the motor runs:
![](/static/2016-10-13_works.png)
But sometimes not:
![](/static/2016-10-13_works_not.png)
The firmware is available here [https://gitea.hottis.de/wn/inverter0](https://gitea.hottis.de/wn/inverter0) and [https://gitea.hottis.de/wn/inverter0ctrl](https://gitea.hottis.de/wn/inverter0ctrl).

View File

@ -0,0 +1,37 @@
<!--
title: Stratum 1 NTP Server participating in ntppool.org
date: 2025-03-13
-->
![](https://numbers.hottis.de/ntp/packets-load.png)
![](https://numbers.hottis.de/ntp/stratum-rootdisp.png)
[Details at ntppool.org](https://www.ntppool.org/scores/93.241.86.156)
## Harrison
![](/static/IMG_6089.jpg)
![](/static/IMG_6088.jpg)
Setup details for this machine are here: [https://gitea.hottis.de/wn/harrison-setup](https://gitea.hottis.de/wn/harrison-setup).
The snmpd subagent for monitoring the ntp daemon is here: [https://gitea.hottis.de/wn/snmp-agentx-ntpsec](https://gitea.hottis.de/wn/snmp-agentx-ntpsec).
### Details of Setup
A GPS receiver (ublox Neo-6M) is connected via a RS232 level converter (MAX232) and via the RS232 connection to a machine (it was not easy to find one with RS232) with a Debian installation.
The PPS signal of the GPS receiver is transmitted via the DCD line of the RS232 connection. That in turn is evaluated by the NMEA line discipline of Linux.
The GPS receiver is then configured as a reference clock in ntpsec:
```
refclock nmea unit 0 mode 0x10 minpoll 4 maxpoll 4 path /dev/ttyS0 ppspath /dev/pps0 baud 9600 flag1 1 flag2 1 flag3 0 refid LIgp
```
## David
![](/static/IMG_6045.jpg)
Details on the setup of this machine are described here: [https://minimal-setups.de/blog/timeserver/](https://minimal-setups.de/blog/timeserver/).

View File

@ -0,0 +1,129 @@
<!--
title: Just another Stratum 1 Timeserver
date: 2025-02-11
-->
![](/static/IMG_6045.jpg)
This server utilizes `ntpsec` on Debian on a BeagleBone Black with a UBlox GPS module.
It has been joined the NTP pool, the statistics are available at [https://www.ntppool.org/scores/93.241.86.156](https://www.ntppool.org/scores/93.241.86.156).
Some additional statistics graphs for the server are available at [https://numbers.hottis.de/ntpserver](https://numbers.hottis.de/ntpserver).
## Preparation of the BeagleBone
The GPS module is connected via serial line to the UART of the BB.
The additional connection of the PPS output with the PPS device of the Linux running on the BB via a GPIO must be prepared. A device tree overlay must be created and compiled:
```
/dts-v1/;
/plugin/;
/{
compatible = "ti,beaglebone", "ti,beaglebone-black";
part_number = "WN-PPS";
version = "00A0";
exclusive-use =
"P8.7",
"gpio2_2";
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
bs_pinmode_P8_7_0x27: pinmux_bs_pinmode_P8_7_0x27 {
pinctrl-single,pins = <0x090 0x27>;
};
};
};
fragment@1 {
target = <&ocp>;
__overlay__ {
bs_pinmode_P8_7_0x27_pinmux {
compatible = "pps-gpio";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bs_pinmode_P8_7_0x27>;
gpios = <&gpio2 2 0>;
assert-rising-edge;
};
};
};
};
```
This file shall be compiled using
```
dtc -O dtb -o WN-PPS-00A0.dtbo -b 0 -@ WN-PPS-00A0.dts
```
The binary dtbo file then copied into `/lib/firmware` and mentioned in the `/boot/uEnv.txt`:
```
uboot_overlay_addr0=/lib/firmware/WN-PPS-00A0.dtbo
```
After a reboot the device file `/dev/pps0` should be available and using `ppstest /dev/pps0` you can test the connection:
```
root@david:/boot# ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1739442756.999984966, sequence: 306598 - clear 0.000000000, sequence: 0
source 0 - assert 1739442757.999978472, sequence: 306599 - clear 0.000000000, sequence: 0
source 0 - assert 1739442758.999976057, sequence: 306600 - clear 0.000000000, sequence: 0
^C
root@david:/boot#
```
## Configuration of the ntpsec daemon
```
interface listen all
logconfig +all
logfile /var/log/ntp.log
statsdir /var/log/ntpsec/
statistics loopstats peerstats clockstats protostats sysstats rawstats
filegen loopstats file loopstats type day disable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable
filegen protostats file protostats type day enable
filegen sysstats file sysstats type day enable
filegen rawstats file rawstats type day disable
driftfile /var/lib/ntpsec/ntp.drift
leapfile /usr/share/zoneinfo/leap-seconds.list
tos maxclock 11
tos minclock 4 minsane 3
refclock nmea unit 0 prefer mode 0x10 minpoll 4 maxpoll 4 path /dev/ttyO4 ppspath /dev/pps0 baud 9600 flag1 1 refid BBgp
# refclock shm unit 0 refid BBg minpoll 4 maxpoll 4 time1 0.1555
# refclock shm unit 2 refid BBp minpoll 4 maxpoll 4 prefer
# refclock pps unit 0 prefer refid BBp ppspath /dev/pps0 minpoll 4 maxpoll 4
# refclock gpsd unit 0 prefer refid BBgp mode 1 minpoll 4 maxpoll 4
server ntps1-1.uni-erlangen.de
server ntps1-0.cs.tu-berlin.de
server ptbtime1.ptb.de
server rustime01.rus.uni-stuttgart.de
server ntp1.sda.t-online.de
server ntps1.gwdg.de
restrict default kod nomodify nopeer noquery limited notrap
restrict 127.0.0.1
restrict ::1
```
Although the `nmea` reference clock driver is obsolete according to [https://ntpsec.org/removal-plan.html](https://ntpsec.org/removal-plan.html), it works perfectly for me, in particular better then the other drivers. However, maybe I was not trying hard enough with the others.

View File

@ -0,0 +1,15 @@
<!--
title: Quotes
-->
# Quotes
Und dann in deinem Arm, alles gut, alles andere egal
(Dota Kehr, Alles Du)
Es ist immer was los, aber es passiert nichts.
(Thadeuz, Steinhammer)
Sie steht gut da. Aber die Seele setzt sich nicht dazu.
(Thadeuz, Steinhammer)