commit 8091fdc5a741f4637cc9aa6da8452dc8b60a110b Author: error Date: Sun Aug 28 18:56:24 2022 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bacca8e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +output/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..23fcca7 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# undefinedbehavior-website + +Content for [undefinedbehavior.de](undefinedbehavior.de). + +## Deployment + +Clone the repository and generate the website using `pelican content -s publishconf.py`. +Refer to the [pelican documentation](https://docs.getpelican.com/en/latest/settings.html "Settings - Pelican") for details on how to configure pelican. + +## Filters + +In order to use sidenotes and lightboxes, add `filters.py` as custom jinja filters to your `pelicanconf.py`: + + from sys import path + from os import curdir + path.append(curdir) + from filters import add_lightboxes, add_sidenotes + + JINJA_FILTERS = {'add_lightboxes': add_lightboxes, + 'add_sidenotes': add_sidenotes} + +## License + +Most content on this site is licensed unter the [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/ "Creative Commons - Attribution-NonCommercial 4.0 International") license. diff --git a/content/favicon.svg b/content/favicon.svg new file mode 100644 index 0000000..9af5364 --- /dev/null +++ b/content/favicon.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/content/pages/contact.md b/content/pages/contact.md new file mode 100644 index 0000000..2247e36 --- /dev/null +++ b/content/pages/contact.md @@ -0,0 +1,27 @@ +Title: Contact +Date: 2022-08-28 16:05 +Author: Error +Status: published +Summary: Information on how to contact me + +## Mail + +My mail address is `error[at]mail.undefinedbehavior.de`. If you are using PGP, please encrypt your mails to me. You can find my PGP key here: + + -----BEGIN PGP PUBLIC KEY BLOCK----- + + mDMEYwtp4hYJKwYBBAHaRw8BAQdA1XZSdSIar5uXBMQeZz9/Yy76Prgm7eIUbTLC + +JphwPe0J0Vycm9yIDxlcnJvckBtYWlsLnVuZGVmaW5lZGJlaGF2aW9yLmRlPoiW + BBMWCAA+FiEEcndbgp2G18V3Liw84XAaKTGUmKcFAmMLaeICGwMFCQWjmoAFCwkI + BwIGFQoJCAsCBBYCAwECHgECF4AACgkQ4XAaKTGUmKeFLAEAtZQkfqD5WCi61Z6z + Nc5AbsFbtp3+i/SAcrBDTSSz8HwA/i/WYcAF/aiBQhOGmmChXVasBN6gwkH06zsj + wZOsa9kGuDgEYwtp4hIKKwYBBAGXVQEFAQEHQBiFyE8NTV/11+OYqmLoLAQhyOnN + 3rP8hz/Ge0MBPLgPAwEIB4h+BBgWCAAmFiEEcndbgp2G18V3Liw84XAaKTGUmKcF + AmMLaeICGwwFCQWjmoAACgkQ4XAaKTGUmKcrZwD7Bg7BI/xHF+GsOZaLq9+6vExb + gynNULdp+6RzjtQqeBoA/A113EFA2XBPATWJfZmmUGHAxWvhcGqLIDACwbnWaPEJ + =+u+A + -----END PGP PUBLIC KEY BLOCK----- + +## Mastodon + +You can find me on chaos.social as @Error. diff --git a/content/pages/credits.md b/content/pages/credits.md new file mode 100644 index 0000000..16d4ed9 --- /dev/null +++ b/content/pages/credits.md @@ -0,0 +1,17 @@ +Title: Credits +Date: 2022-08-28 16:05 +Author: Error +Status: hidden +Summary: Credit where credit is due + +## Pelican + +This site is powered by [Pelican](https://getpelican.com "Pelican Static Site Generator, Powered by Python"). Pelican is a static site generator written in python. +It's licensed under the [GNU Affero General Public License v3.0](https://www.gnu.org/licenses/#AGPL "GNU Affero General Public License") + +## LATEX.css + +This site's template is based on [LATEX.css](https://latex.now.sh "LaTeX.css"), a CSS library that makes a website look like a LaTeX document. +LATEX.css is licensed under the MIT License. + +The template can be found [here](https://git.undefinedbehavior.de/undef/undefined-pelican-theme "Undefined Pelican Theme"). diff --git a/content/pages/imprint.md b/content/pages/imprint.md new file mode 100644 index 0000000..d88db84 --- /dev/null +++ b/content/pages/imprint.md @@ -0,0 +1,16 @@ +Title: Imprint +Date: 2022-08-28 16:05 +Author: Error +Status: hidden +Summary: Legaly required contact information + +## Disclaimer + +This information is only provided for legal reasons. Please reach out to me via [e-mail or Mastodon](/pages/contact "Contact") instead. It's much faster and simpler. + +## Verantwortlich gemäß §5 TMG + + Felix Hallaczek + Heilmannstraße 4b + 70190 Stuttgart + Germany diff --git a/content/pages/privacy.md b/content/pages/privacy.md new file mode 100644 index 0000000..b93339d --- /dev/null +++ b/content/pages/privacy.md @@ -0,0 +1,15 @@ +Title: Privacy +Date: 2022-08-28 16:05 +Author: Error +Status: hidden +Summary: Only necessary data is processed. No logging, no tracking, no analytics; + +## Privacy Statement + +This website only processes data that is necessary in order to fulfill the user's request, e.g. the user's IP address. +It does not generate access logs. +Personal data is discarded once the request was served. + +This server only serves requests via HTTPS. All communication is end-to-end encrypted with TLS. Requests received on port 80 (HTTP) are redirected to port 443 (HTTPS). + +If you're interested in more information on how this webside is delivered to your device, have a look at [RFC 9112](https://datatracker.ietf.org/doc/html/rfc9112 "HTTP/1.1") for HTTP/1.1 and [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446 "The Transport Layer Security (TLS) Protocol Version 1.3") for TLS 1.3. diff --git a/content/posts/scroip.md b/content/posts/scroip.md new file mode 100644 index 0000000..3490d8b --- /dev/null +++ b/content/posts/scroip.md @@ -0,0 +1,87 @@ +Title: Slot Car Racing over IP (SCRoIP) +Date: 2022-08-28 16:05 +Author: Error +Slug: scroip +Summary: I built a remote control for a slot car racing track to play with it over the LAN. It's unnecessary complicated and inefficient, but at least it supports IPv6. Ladies, Gentlemen and everyone else, start your engines. +License: CC-BY-NC + https://creativecommons.org/licenses/by-nc/4.0/ + +## The Idea + +When I was a child, I used to play a lot with my slot car racing track. +After stubling upon it again recently, I started wondering if I could build something to control it over the network. +Not that I needed a remote control for it, but it seemed like a fun project. +However, simply creating an API that offers precise control over the device seemed way to sriaght forward - the controling mechanism itself should add its challenges. +So I came up with the idea to control it with the traffic itself. +The more traffic is sent to the remote control, the faster the car is supposed to go.[°Use more bandwidth!!!] + +## Reversing + +In order to build the remote control, the first step was to figure out how the slot car racing system works. So I disassembled it and took a look at its wiring. + +![Simplified circuit diagram for a slot car racing system]({static}/posts/scroip/carrera.svg "Simplified circuit diagram of a slot car racing system") + +The underlying mechanism is fairly simple. The power supply provides about 14.8 V DC voltage, which a used to power the car's motor. +The speed of the car is controlled by a variable resistor within the controller, which allows to control the voltage the car receives. +Pushing the controller further down lowers the resistance, which raises the voltage available to the car and makes is go faster. +A third wire is used to brake the car when the controller is in its neutral position by utilizing the current generated by the motor when the car is rolling out. +A look at wikipedia confirms this analysis. [^1] + +## Building a digital Controller + +Now that I understood the mechanism, the next step was to create a digital version of it, so that I could control the slot car racing track with a Raspberry Pi. +My first idea was to simply use a digital potentiometer. +However, searching for a suitable digipot, I quickly realized that there were no options with the desired dimensions of about 30 Ω available. +Therefore I built it myself using a few resistors, solid state relais and multiplexers.[°I'm sure there are simpler solutions for this, but, well, it worked for me.] + +![SCRoIP controller circuit diagram]({static}/posts/scroip/scroip.svg "SCRoIP controller circuit diagram") + +For the sake of simplicity,[°or maybe out of laziness, who knows? :)] I did not add the braking mechanism from the analog controller to my digital version. + +## Implementing the Server + +With the hardware fully assembled and soldered, it was time to have a look at the software. +Python offers an easy way of implementing TCP servers.[°This project will use TCP. Even though the payload is immediately discarded, reliability is of the utmost importance and packet loss will not be accepted!!!] +By default, it only supports IPv4, but IPv6 support can be added by setting `address_family` to `AF_INET6`. + + if not legacy: + self.address_family = AF_INET6 + super(SCRoIPServer, self).__init__((address, port), SCRoIPRequestHandler) + +The server's logic itself is implemented in the method `handle()` of the class `SCRoIPRequestHandler`. While there is an active connection, it reads from the socket and sums up the ammount of data that was received. +Once every 100 ms, it then calculates the average throughput for that time period and sets the raspi's GPIO pins accordingly. + + while self.data != b'': + try: + self.data = self.request.recv(4096) + self.traffic_counter += len(self.data) + except TimeoutError: + pass + + time = clock_gettime_ns(CLOCK_REALTIME) + diff = time - self.last + if (diff > 100000000): + self.last = time + traffic: float = self.traffic_counter / diff * 1000000000 + print(f"{traffic} Bytes/s") + self.server.set_throttle(traffic) + self.server.apply_throttle() + self.traffic_counter = 0 + +The full server code can be found [here](https://git.undefinedbehavior.de/undef/SCRoIP "Slot Car Racing over IP - SCRoIP - undefined git server"). + +## Lights out and away we go + +Once the server was implemented as well, all that was left to do was to test it. +So I deployed the server script to a Raspberry Pi, connected its GPIO pins to the controller and the controller to the slot car racing track. +Using netcat, I was now able to accelerate the car with the network traffic I generated: + + + +[^1]: [https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung](https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung "Autorennbahn – Wikipedia") diff --git a/content/posts/scroip/carrera.svg b/content/posts/scroip/carrera.svg new file mode 100644 index 0000000..5706050 --- /dev/null +++ b/content/posts/scroip/carrera.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + ++ + + + + + + +14 +. +8 +V + + + + + +30 + + + + + +6 +. +8 + +22 +nF + +6 +. +8 + + + + + + +M + + + + \ No newline at end of file diff --git a/content/posts/scroip/demo.webm b/content/posts/scroip/demo.webm new file mode 100644 index 0000000..887b569 Binary files /dev/null and b/content/posts/scroip/demo.webm differ diff --git a/content/posts/scroip/scroip.svg b/content/posts/scroip/scroip.svg new file mode 100644 index 0000000..5e5f529 --- /dev/null +++ b/content/posts/scroip/scroip.svg @@ -0,0 +1,1268 @@ + + + + + + +V +in + + + + + +1 + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +demux0 + + + +demux1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +R +1 + + + + + + + + + + + + + + + + + + + + + + + +A +0 + + + + + + + +A +1 + + + + + + + +A +2 + + + +S +0 + + + + + + +S +1 + + + + + +demux2 + +S +2 + + + + +demux3 + +S +3 + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +V +out + + + + \ No newline at end of file diff --git a/filters.py b/filters.py new file mode 100644 index 0000000..dd9d322 --- /dev/null +++ b/filters.py @@ -0,0 +1,54 @@ +def add_lightboxes(html: str, + lightbox_class: str = "lightbox", + wrapper_class: str = "lightbox-wrapper") -> str: + counter: int = 0 + img_start: int = html.find(" -1: + counter += 1 + img_end: int = html.find(">", img_start + 4) + lightbox: str = f"\n" +\ + f"
\n" +\ + f" \n" +\ + f" {html[img_start:img_end + 1]}\n" +\ + f" \n" + alt_start: int = html.find("alt=\"", img_start + 4) + if alt_start > -1: + alt_end: int = html.find("\"", alt_start + 5) + lightbox = lightbox + f"
\n" +\ + f" {html[alt_start + 5:alt_end]}\n" +\ + f"
\n" + lightbox = lightbox + f"
\n" +\ + f"
\n" +\ + f" \n" +\ + f" [close]\n" +\ + f" \n" +\ + f" {html[img_start:img_end + 1]}\n" +\ + f"
\n" +\ + f"
\n" +\ + f"
\n" + if html[img_start - 3:img_start] == "

" and html[img_end + 1:img_end + 5] == "

": + img_start -= 3 + img_end += 4 + html = html[:img_start] + lightbox + html[img_end + 1:] + img_start = html.find(" str: + counter: int = 0 + start: int = html.find("[°") + while start > -1: + counter += 1 + end: int = html.find("]", start) + text: str = html[start + 2:end] + sidenote: str = f"\n" +\ + f"\n" +\ + f"\n" +\ + f" {text}\n" +\ + f"\n" + html = html[:start] + sidenote + html[end + 1:] + start = html.find("[°", start + len(sidenote)) + return html diff --git a/pelicanconf.py b/pelicanconf.py new file mode 100644 index 0000000..438709b --- /dev/null +++ b/pelicanconf.py @@ -0,0 +1,53 @@ +from sys import path +from os import curdir +path.append(curdir) +from filters import add_lightboxes, add_sidenotes + +AUTHOR = 'Error' +SITENAME = 'Undefined Behavior' +SITEURL = '' +ABSTRACT = "If, as Adam Savage famously put it, the only difference between screwing around and science is writing it down, I should probably write about my projects somewhere. I'll just do it here." +FAVICON = 'favicon.svg' +STATIC_PATHS = ['favicon.svg'] + +TIMEZONE = 'Europe/Rome' +DEFAULT_DATE_FORMAT = '%Y-%m-%d' +DEFAULT_LANG = 'en' + +THEME = 'undefined-pelican-theme' +PATH = 'content' + +ARTICLE_URL = 'posts/{slug}/' +ARTICLE_SAVE_AS = 'posts/{slug}/index.html' +PAGE_URL = 'pages/{slug}/' +PAGE_SAVE_AS = 'pages/{slug}/index.html' +AUTHOR_URL = '' +AUTHOR_SAVE_AS = '' +AUTHORS_SAVE_AS = '' +CATEGORY_URL = '' +CATEGORY_SAVE_AS = '' +CATEGORIES_SAVE_AS = '' +TAG_URL = '' +TAG_SAVE_AS = '' +TAGS_SAVE_AS = '' +ARCHIVES_SAVE_AS = '' + +# Feed generation settings +FEED_ALL_ATOM = 'feeds/atom.xml' +CATEGORY_FEED_ATOM = None +TRANSLATION_FEED_ATOM = None +AUTHOR_FEED_ATOM = None +AUTHOR_FEED_RSS = None + +LINKS = (('credits', '/pages/credits'), + ('imprint', '/pages/imprint'), + ('privacy', '/pages/privacy'),) + +DEFAULT_PAGINATION = False + +# dev settings +RELATIVE_URLS = True +DELETE_OUTPUT_DIRECTORY = True + +JINJA_FILTERS = {'add_lightboxes': add_lightboxes, + 'add_sidenotes': add_sidenotes} diff --git a/publishconf.py b/publishconf.py new file mode 100644 index 0000000..a6db35d --- /dev/null +++ b/publishconf.py @@ -0,0 +1,9 @@ +from sys import path +from os import curdir +path.append(curdir) + +from pelicanconf import * + +SITEURL = 'https://undefinedbehavior.de' +PATH = '/var/www/virtual/undef/html' +RELATIVE_URLS = False