added flicker.sh
authorAndreas Schiermeier <andreas@schiermeier.name>
Sat, 16 Jun 2012 22:25:37 +0000 (00:25 +0200)
committerAndreas Schiermeier <andreas@schiermeier.name>
Sat, 16 Jun 2012 22:25:37 +0000 (00:25 +0200)
chiptan/flicker/flicker.sh [new file with mode: 0644]

diff --git a/chiptan/flicker/flicker.sh b/chiptan/flicker/flicker.sh
new file mode 100644 (file)
index 0000000..7066293
--- /dev/null
@@ -0,0 +1,237 @@
+#!/bin/bash
+
+# Flickergenerator
+# Andreas Schiermeier <andreas@schiermeier.name>
+
+# Abbruch bei RC != 0 eines Befehls
+set -e
+# Fehlermeldung beim Zugriff auf nicht-initialisierte Variablen
+set -u
+
+LANG="C"
+
+# Wer bin ich?
+typeset    ME="${0##*/}"
+
+# HIGH-Farbe (weiss auf schwarz)
+typeset    HIGH="$(echo -e '\033[48;05;15m')"
+# LOW-Farbe (schwarz auf schwarz)
+typeset    LOW="$(echo -e '\033[48;05;0m')"
+# Standardfarben
+typeset    STD="$(echo -e '\033[0m')"
+
+# Config, wenn vorhanden, einlesen
+[ -r "${HOME}/.${ME}.cfg" ] && source "${HOME}/.${ME}.cfg"
+
+# Breite eines Datenfeldes (ein Bit)
+typeset -i FIELDW=${CFG_FIELDW:-3}
+# Abstand zwischen Datenfeldern
+typeset -i SPACEW=${CFG_SPACEW:-3}
+# Höhe von Datenfeldern
+typeset -i HEIGHT=${CFG_HEIGHT:-1}
+# Flickerdaten
+typeset    FLICKERDATA=""
+# enthält clear-Steuersequenz wenn vor jedem Frame der Bildschrim geleert werden soll
+typeset    CLEAR="${CFG_CLEAR-""}"
+# Wartezeit zwischen Frames
+typeset    WAIT="${CFG_WAIT:-"0.05"}"
+
+# Initialisierungssequenz des Flickercodes
+typeset    FLICKERSYNC="10000 00000 11111 01111 11111 01111 11111"
+
+# enthalt später Flickerinitialisierung & -daten in Binärdarstellung
+typeset    FLICKERSTREAM=""
+
+# Standardfarben des Terminals
+typeset    S=""
+# HIGH-Sequenz n-Leerzeichen hell auf schwarzem Hintergrund
+typeset    H=""
+# HIGH-Sequenz n-Leerzeichen schwarz auf schwarzem Hintergrund
+typeset    L=""
+
+typeset    PREFIX=""
+typeset    SUFFIX=""
+
+# Sequenz als Nibbles vereinzelt und mit Taktsignal versehen
+typeset    clknibbles=""
+
+# Fertige Sequenz mit ANSI-Escapes
+typeset    frames=""
+
+# Laufzeitparametrisierung
+typeset    nextctl=""
+
+
+function usage {
+  echo
+  echo "${ME} -d Daten [-h Feldhoehe] [-w Feldbreite] [-s Abstand] [-t Wartezeit] [-c]"
+  echo
+  typeset optfmt='  -%s %-10s: %s\n'
+  printf "${optfmt}" "d" "Daten" "Übergabe der Flickerdaten"
+  printf "${optfmt}" "h" "Feldhoehe" "Feldhöhe in Zeilen"
+  printf "${optfmt}" "w" "Feldbreite" "Feldbreite in Zeichen"
+  printf "${optfmt}" "s" "Abstand" "Abstand in Zeichen zwischen Feldern"
+  printf "${optfmt}" "t" "Wartezeit" "Wartezeit zwischen Frames in Sekunden. \".\" als Dezimaltrenner."
+  printf "${optfmt}" "c" " " "Bildschirm löschen vor jeder Sequenz (\"bankenähnliche Ausgabe\")"
+  cat <<__EOF
+
+Zur Laufzeit können mit den Buchstaben h, w, s, t, c gefolgt von + oder - die Parameter
+beeinflusst werden. Mit q werden die aktuellen Parameter in ~/.${ME}.cfg gesichert.
+
+__EOF
+}
+
+# erstellt Flickersequenz mit ANSI Escapesequenzen
+function buildSeq {
+  S=$(printf "%s%${SPACEW}s" "${LOW}" " ")
+  H=$(printf "%s%${FIELDW}s%s" "${HIGH}" " " "${S}")
+  L=$(printf "%s%${FIELDW}s%s" "${LOW}" " " "${S}")
+
+  frames="${clknibbles}"
+
+  # in den Escape-Sequenzen von ${L} und ${H} können 0 und 1 vorkommen.
+  # Mit dem Tausch von 0 zu L und 1 zu H wird sichergestellt, dass nicht Teile der
+  # Escape-Sequenz ersetzt werden
+  frames="${frames//0/L}"
+  frames="${frames//1/H}"
+
+  # L & H in korrespondierende Escape-Sequenzen umsetzen
+  frames="${frames//L/${L}}"
+  frames="${frames//H/${H}}"
+
+  PREFIX="${LOW}|${S}"
+  SUFFIX="|${STD}"
+}
+
+# writeDefaults speichert aktuelle Flickering-Parameter (Breiten, Frequenz, etc.)
+function writeConfig {
+  cat << "__EOF" > "${HOME}/.${ME}.cfg"
+# Breite eines Datenfeldes (ein Bit)
+CFG_FIELDW="${FIELDW}"
+# Abstand zwischen Datenfeldern
+CFG_SPACEW="${SPACEW}"
+# Höhe von Datenfeldern
+CFG_HEIGHT="${HEIGHT}"
+# Flickerdaten
+CFG_CLEAR="${CLEAR}"
+# Wartezeit zwischen Frames
+CFG_WAIT="${WAIT}"
+__EOF
+}
+
+if [ ${#} -eq 0 ]
+then
+  usage
+  exit 0
+fi
+
+while getopts "d:h:w:s:t:c" opt
+do
+  case "${opt}" in
+    d) FLICKERDATA="${OPTARG}";;
+    h) HEIGHT="${OPTARG}";;
+    w) FIELDW="${OPTARG}";;
+    s) SPACEW="${OPTARG}";;
+    t) WAIT="${OPTARG}";;
+    c) CLEAR="$(clear)";;
+    *) usage >&2
+       echo "Fehler: Unbekannte Option \"${opt}\"" >&2
+       exit 1
+       ;;
+  esac
+done
+shift $((OPTIND - 1))
+
+if [ ${#} -ne 0 ]
+then
+  usage >&2
+  echo "Fehler: Unbekannte Option \"${@}\". Abbruch." >&2
+  exit 1
+fi
+
+if [ -z "${FLICKERDATA}" ]
+then
+  echo "Fehler: keine Flickerdaten (-d) übergeben." >&2
+  exit
+fi
+
+# Eingabedaten bereinigen ("0x" von Zahlen entfernen, Leerzeichen entfernen) und neu ordnen; F004.. => 0F40...
+FLICKERDATA="$(echo "${FLICKERDATA}" | \
+                  sed 's/0[xX]//g;
+                       s/ //g;
+                       s/\([0-9a-fA-F]\)\([0-9a-fA-F]\)/\2\1/g;'
+  )"
+
+FLICKERSTREAM="${FLICKERSYNC} $(
+  echo -n "${FLICKERDATA}" | while read -n1 hex
+  do
+    i=0
+    printf " %04i" $(((0x${hex} & 2**(i) && 1 ) * 10**(3-i++) +
+                      (0x${hex} & 2**(i) && 1 ) * 10**(3-i++) +
+                      (0x${hex} & 2**(i) && 1 ) * 10**(3-i++) +
+                      (0x${hex} & 2**(i) && 1 ) * 10**(3-i++)
+                    ))
+  done
+  )"
+
+# Nibbles ohne Takt-Bit in zwei Frames mit Takt umsetzen
+for nibble in ${FLICKERSTREAM}
+do
+  case "${nibble}" in
+    ????)
+      clknibbles="${clknibbles}${clknibbles:+|}1${nibble}|0${nibble}";;
+    *)
+      clknibbles="${clknibbles}${clknibbles:+|}${nibble}";;
+  esac
+done
+
+buildSeq
+
+while true
+do
+  IFS="|"
+  for frame in ${frames}
+  do
+    echo -n "${CLEAR}"
+    for (( i=0; i<HEIGHT; i++ )) {
+      echo "${PREFIX}${frame}${SUFFIX}"
+    }
+
+   # 2-in-1: 1. Timer (-t ${WAIT}) zwischen den Frames
+   #         2. Annahme von Befehlen
+   # wird kein Befehls-Zeichen gelesen, wird mit "continue" der verbleibende
+   # Schleifenkörper übersprungen und zum nächsten Frame übergegangen
+   read -s -N 1 -t ${WAIT} ctl || continue;
+   case "${ctl}" in
+     q) writeConfig
+        exit 0
+        ;;
+     h|w|s|t|c) nextctl="${ctl}";;
+     +) case "${nextctl}" in
+          h) let HEIGHT++;;
+          w) let FIELDW++;;
+          s) let SPACEW++;;
+          t) [ $WAIT != ".01" ] && WAIT=$(echo "${WAIT}-0.01" | bc -q);;
+          c) CLEAR="$(clear)";;
+        esac
+        # Flickersequenz mit den geänderten Parametern erstellen
+        buildSeq;
+        # Flickersequenz vom Anfang starten indem der aktuelle Durchlauf der 
+        # while- UND for-Schleife übersprungen wird
+        continue 2
+        ;;
+     -) case "${nextctl}" in
+          h) [ $HEIGHT -gt 1 ] && let HEIGHT--;;
+          w) [ $FIELDW -gt 1 ] && let FIELDW--;;
+          s) [ $SPACEW -gt 1 ] && let SPACEW--;;
+          t) WAIT=$(echo "${WAIT}+0.01" | bc -q);;
+          c) CLEAR="";;
+        esac
+        # Flickersequenz mit den geänderten Parametern erstellen
+        buildSeq
+        # Flickersequenz vom Anfang starten (siehe oben)
+        continue 2
+        ;;
+   esac
+  done
+done