staging.inyokaproject.org

Integer und String über eine serielle Schnittstelle ausgeben

Status: Ungelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Wenn du in eine ASCII-Tabelle schaust, siehst du, dass ein S den Dezimal-Wert 83 bzw. den Hex-Wert 0x53 hat:

$ printf '%02x\n' 83
53
$ echo $'\x53'
S
$ echo -n  $'\x53' | od -x
0000000 0053
0000001 

Damit ist das bei gleicher Byte-Reihenfolge am Zielgerät eigentlich genau das was du willst - das Low-Byte enthält die Information.

Zur Erklärung: die Bash erlaubt es mit dem \x-Prefix 8-Bit Zeichen anzugeben (vgl. info bash, Abschnitt zum Quoting):

       Words  of  the  form  $'string' are treated specially.  The word expands to string, with backslash-escaped
       characters replaced as specified by the ANSI C standard.  Backslash  escape  sequences,  if  present,  are
       decoded as follows:
              [...]
              \nnn   the eight-bit character whose value is the octal value nnn (one to three digits)
              \xHH   the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
              \uHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four
                     hex digits)
              \UHHHHHHHH
                     the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one  to
                     eight hex digits)
              \cx    a control-x character

       The expanded result is single-quoted, as if the dollar sign had not been present.

       A  double-quoted  string  preceded  by  a  dollar  sign ($"string") will cause the string to be translated
       according to the current locale.  If the current locale is C or POSIX, the dollar sign is ignored.  If the
       string is translated and replaced, the replacement is double-quoted.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@fllopi: Nein das ist nicht zu viel denn Du willst ja nicht die Zeichenkette '53' senden, die aus zwei Bytes besteht, sondern ein Byte mit dem Wert 83 (dezimal) beziehungsweise 53 (hexadezimal). Und dieser Wert als Zeichen ist ein grosses 'S'. Da der Wert unter 128 liegt, kannst Du das in der ASCII-Tabelle nachlesen. Oder anders herum: Das Zeichen 'S' hat den Bytewert 83 (dezimal).

fllopi

(Themenstarter)

Anmeldungsdatum:
31. August 2015

Beiträge: 26

Ok habe es erst einmal so weit verstanden vielen dank euch allen 😀 Ich werde es hoffentlich in den nächsten Tagen noch testen können.

fllopi

(Themenstarter)

Anmeldungsdatum:
31. August 2015

Beiträge: 26

Ich hatte es nun getestet und es geht schon am Anfang nicht -_- Aber habe ich es richtig verstanden? Der Befehl

1
echo -e "\x$(printf '%02x' "5")" >> /dev/ttyS0

sendet einen Byte an die Serielle schnittstelle. Das Problem könnte doch sein das der Wert 5 im nicht darstellbarem Bereich liegt und ich versuche das Zeichen zu senden. Mit anderen Worten ich versuche etwas darzustellen was nicht darzustellen geht.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

Einmal sollte doch das Newline unterdrückt werden:

1
echo -en "\x5"

Zum anderen verstehe ich nicht, wieso Du echo und printf schachtelst.

Was kann man damit erreichen? Einfach:

1
echo -en "\x5" >> /dev/ttyS0
1
2
3
4
for foo in {0..255}
do 
  echo -en "\x$foo" >> /dev/ttyS0
done 

Das sollte nacheinander alle Bytes von 0 bis 255 verschicken.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

fllopi schrieb:

Ich hatte es nun getestet und es geht schon am Anfang nicht -_-

Was genau hast Du getestet? Richtig fragen

Aber habe ich es richtig verstanden? Der Befehl

1
echo -e "\x$(printf '%02x' "5")" >> /dev/ttyS0

sendet einen Byte an die Serielle schnittstelle.

Tatsächlich zwei Bytes. Du kannst das einfach mit den hier bereits schon genannten Werkzeugen nachvollziehen. Probier das doch einfach mal aus:

1
2
3
4
$ echo -e "\x$(printf '%02x' "5")" | od -tx1c
0000000  05  0a
        005  \n
0000002

Da sieht man schon, dass ein Zeichen zu viel gesendet wird.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@user_unknown: Dein zweites Beispiel funktioniert nicht weil foo die Dezimaldarstellung von den Zahlen enthält, hinter dem \x aber die Hexadezimaldarstellung stehen muss. Da wird dann vielleicht auch der Sinn der Schachtelung von printf und echo klar: printf wandelt die Dezimaldarstellung in die Hexadezimaldarstellung um. Wenn man einen festen Wert hat, kann man gleich '\x05' schreiben, aber wenn man eine Variable mit einem Wert in Dezimalschreibweise hat…

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

Marc_BlackJack_Rintsch schrieb:

@user_unknown: Dein zweites Beispiel funktioniert nicht weil foo die Dezimaldarstellung von den Zahlen enthält, hinter dem \x aber die Hexadezimaldarstellung stehen muss. Da wird dann vielleicht auch der Sinn der Schachtelung von printf und echo klar: printf wandelt die Dezimaldarstellung in die Hexadezimaldarstellung um. Wenn man einen festen Wert hat, kann man gleich '\x05' schreiben, aber wenn man eine Variable mit einem Wert in Dezimalschreibweise hat…

Ah, ja, jetzt dämmert es mir. Bin zu sehr mit dem Advent-of-Code beschäftigt, um mich tiefer mit anderen Sachen zu beschäftigen. ☺

Aber für eine kleine Bashhandarbeit hat es dann doch gereicht. Ich glaube ich habe ein printf-Trauma. Mir wird schlecht, wenn ich es sehe, aber ich habe keine rationale Begründung. Vielleicht doch - als ich das kennenlernte haben die Compiler nicht in die Ausdrücke reingeschaut und keine Typprüfung gemacht. Heute gibt es äquivalente Befehle bei Scala beispielsweise, da meckert der Compiler, wenn es nicht passt.

1
2
3
4
5
6
7
8
#!/bin/bash
tohex () { 
	val=$1
	hi=$((val/16))
	lo=$((val%16))
	hexis=($(echo {0..9} {a..f}))
	echo -en \x${hexis[hi]}${hexis[lo]}
}

Und der Test:

1
for i in {0..255}; do tohex $i; done | od -tx1c

Eine Absicherung für Werte < 0, größer 255, Nichzahlen usw. fehlt noch. Dafür gibt es das auch als Einzeiler:

1
tohex () {  val=$1; hi=$((val/16)); lo=$((val%16)); hexis=($(echo {0..9} {a..f})); echo -en "\x${hexis[hi]}${hexis[lo]}"; } 

fllopi

(Themenstarter)

Anmeldungsdatum:
31. August 2015

Beiträge: 26

OK, OK das geht. Ich prüfe es an dem Gerät welches durch das Script einen Befehl erhalten soll, welcher demnach ausgeführt werden muss. Was mir nun aber noch aufgefallen ist, ist das ich das was das Gerät zurückgibt wohl auch umwandeln muss, da ich eine if funktion innerhalb meines Skriptes habe. Oder geht das (unter der Voraussetzung das was eingelesen werden soll die Wertigkeit 4d hat)?

1
2
3
4
5
6
7
varA=$(echo -e "\x$(printf '%02x' "4")")
varB=$(cat < /dev/ttyS0)
if [ "varA" = "varB" ]
then
.
.
.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

fllopi schrieb:

Was mir nun aber noch aufgefallen ist, ist das ich das was das Gerät zurückgibt wohl auch umwandeln muss, da ich eine if funktion innerhalb meines Skriptes habe. Oder geht das (unter der Voraussetzung das was eingelesen werden soll die Wertigkeit 4d hat)?

Das entspricht einem Groß-M.

fllopi

(Themenstarter)

Anmeldungsdatum:
31. August 2015

Beiträge: 26

Sorry hatte mich nicht ganz klar ausgedrückt. Ich meinte nicht 4D in Hexadezimal sondern die 4 als Dezimal.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

fllopi schrieb:

Sorry hatte mich nicht ganz klar ausgedrückt. Ich meinte nicht 4D in Hexadezimal sondern die 4 als Dezimal.

Das ist nun auch nicht ganz eindeutig ... was soll dort "dezimal" bedeuten ??

Denn über die (serielle) Schnittstelle gehen nur und ausschließlich hexadezimale Zeichen. (m.a.W.: "pure Zahlen" gibt es dort überhaupt nicht !)
Deshalb war es ja die ganze Zeit die Frage, ob Deine 4 das ASCII-Zeichen 0x4D (="4") sein soll, oder ob Du 0x04 (= Hex-Zahl 04) meinst.

Grundsätzlich ist es sowohl für echo / printf als auch für die Schnittstelle egal, was Du da drüber schickst. Du musst halt nur das richtige 'reinfüttern, dann geht das alles.

LG,

track

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

Nein, über die serielle Schnittstelle gehen Daten. Auf einer technischen Ebene wollen die meisten von uns gar nicht so genau wissen, was das ist. Die Schnittstelle übersetzt es aber für uns in Datenpäckchen, die kleinste Einheit, die wohl ankommt, ist wohl ein Byte. Das können wir zwar wieder bitweise zerlegen, aber ein einzelnes Bit kann man m.W. nicht schicken.

Für Bytes gibt es konventionelle Darstellungsformen und weniger konventionelle, hexadezimal, oktal, dezimal, Buchstaben, Farben, Noten. Der Buchstabe kann eine Ziffer sein, was den Zahlenformaten eine weitere Verwechslungsmöglichkeit zufügt.

  • 0x04 konventionelles Hexadezimalformat

  • 0004 konventionelles, aber weithin unbekanntes Oktalformat

  • 4 dezimal ist in unserer Kultur der Normalfall und ohne Auszeichnung

  • '4' Zeichen, die Ziffer 4

  • '♦' Karozeichen, in alten Asciitabellen für Byte 0x04 oft zu finden, wenn ich recht liege. Hier habe ich etwas aus einer UTF-8-Tabelle für &diams; &diams; verwendet

  • 0000:0100 binäres Format, schlecht zu erraten, solange nicht mindestens ein Bit auf 1 gesetzt ist. ☺

  • IIII simples, römisches Format

  • IV römisches Format mit Komprimierung.

Dass 4d für Dezimal stehen soll ist wirklich schlecht zu erraten. Ich glaube selbst im Matheunterricht, wenn man Zahlenbasen durchnimmt, verwendet man ein Niedriggestelltes d, was die Forensoftware zumindest nicht per Button unterstützt, und ich meine auch als Präfix, nicht Postfix, oder?

Die verbreitete Krankheit jedes Wort, das nicht im Wortschatz eines 3jährigen ist, in Anführungsstriche zu setzen, durchkreuzt aber jeden vernünftigen Versuch damit umzugehen - immerhin sind auch Anführungsstriche als Zeichendarstellung eines Hexadezimalcodes zu interpretieren - das paarweise Auftreten hilft hier aber der Erfassung.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

Über serielle Schnittstellen gehen einzelne Bits. Ob da eventuell eine Hardware zwischen ist, die ein Byte puffert und einen nur ganze Bytes senden/empfangen lässt ist dann noch einmal eine andere Frage. Aber selbst dann können und werden oft noch zusätzliche Bits gesendet und empfangen, zum Beispiel „start“, „parity“, und „stop“ bits, so das beispielsweise 9, 10, oder 11 Bits pro Byte gesendet/empfangen werden. Es kann auch sein das die Hardware erlaubt per Programm jede einzelne Leitung beliebig zu schalten. Dann kann man wirklich einzelne Bits senden und sich eigene Protokolle ausdenken, oder übliche serielle Protokolle rein in Software zu implementieren (Stichwort „bit banging“).

Das Karozeichen (♦) wird wohl eher nicht in einer ASCII-Tabelle stehen. Der Bytewert 4 ist dort das „end of transmission“ (EOT) Steuerzeichen. Das Karozeichen ist normalerweise das 4. Zeichen im IBM VGA-Zeichensatz. Und auch wenn die meisten Programmiersprachen unter DOS den Bytewert einfach unverändert weiterreichen für die Ausgabe und dann so ein Karo auf dem Bildschirm steht, ist das an der Stelle kein Wert der offiziell in einer der Codepages auftaucht, denn die sind als Obermenge von ASCII definiert. Man kann also das Karozeichen beispielsweise nicht in CP437 (die normale Kodierung von DOS) oder CP850 (deutsche Kodierung für DOS) konvertieren:

$ echo ♦ | iconv -f utf8 -t cp437
iconv: illegal input sequence at position 0
$ echo ♦ | iconv -f utf8 -t cp850
iconv: illegal input sequence at position 0

Und umgekehrt wird aus einem Bytewert 4 auch kein Karozeichen in UTF-8, sondern das bleibt der Bytewert 4:

$ echo -ne '\x04' | iconv -f cp437 -t utf8 | hd
00000000  04                                                |.|
00000001

Das tiefgestellte „d“ als Notation kenne ich übrigens nicht aus Mathe, bei uns wurde die Zahlenbasis tiefergestellt angehängt. Also beispielsweise 4d₁₆=77₁₀=115₈=1001101₂. Für die tiefgestellten Zahlen habe ich die Forensoftware übrigens gar nicht gebraucht, das sind eigene Zeichen in Unicode. ☺

Antworten |