Umwandlung von 8bit zu 7bit

Schnelle objektorientierte, kompilierende Programmiersprache.
mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von mfro » Do Feb 13, 2014 1:54 pm

Weil Du dir erstens ein recht interessantes, aber zweitens meiner Ansicht nach für einen C-Anfänger etwas zu schwieriges Problemchen ausgesucht hast, mach' ich jetzt mal was, was ich normalerweise nicht machen würde: ein "fertiges" Beispielprogramm liefern.

Vielleicht können wir an dem gemeinsam nachvollziehen, wie das funktioniert.

Das ist nicht die einzige (und bestimmt nicht die beste) Art und Weise, wie man das implementieren kann, aber es funktioniert, und das ist erst mal die Hauptsache:

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/*
 * Binärdump eines Strings
 */
void bitdump(const char *str)
{
    char bitchar[9];
    do {
        char *cp = bitchar;
        int i;

        for (i = 7; i >= 0; i--)
        {
            *cp++ = ((*str >> i) & 1 ? '1' : '0');
        }
        *cp++ = '\0';

        printf("%s ", bitchar);
    } while (*str++);
}

/*
 * Hexdump eines Strings
 */
void hexdump(const char *str)
{
    do {
        printf("%02x ", *str & 0xff);
    } while (*str++);
}

/*
 * Array mit Masken entsprechend der Bitpositionen
 *
 * ACHTUNG: in oktaler Darstellung!
 */
static const unsigned char mask[] =
{
    0001,   /* 00000001 */
    0003,   /* 00000011 */
    0007,   /* 00000111 */
    0017,   /* 00001111 */
    0037,   /* 00011111 */
    0077,   /* 00111111 */
    0177,   /* 01111111 */
};

bool oct2sept(char *sept, const char *oct)
{
    int pos = 0;                                        /* hält die Zeichenposition im String Modulo 8 */

    do {
        if (*oct & 0x80)                                /* Fehler: Bit 7 ist gesetzt - String nicht codierbar */
            return false;

        *sept = *oct >> pos;                            /* Zeichen kopieren und nichtgenutzte niederwertige Bits (die */
                                                        /* schon im vorigen Byte abgehandelt sind) abhängig von der */
                                                        /* Position im String wegshiften */
        *sept |= (*(oct + 1) & mask[pos]) << (7 - pos); /* den "links freigewordenen" Platz mit den Bits des nächsten Zeichens auffüllen */

        if (pos != 7)                                   /* nach 7 Zeichen haben wir eins eingespart */
            sept++;

        pos = (pos + 1) % 8;                            /* Zeichenposition updaten */
    } while (*oct++);
    *sept = '\0';

    return true;
}


int main(int argc, const char *argv[])
{
    const char *octs = "Eine etwas laengere Mitteilung";
    char septs[160];
    (void) argc;
    (void) argv;

    bitdump(octs);
    puts("");

    if (oct2sept(septs, octs))
    {
        printf("\"%s\" in 7-Bit-Darstellung:\n", octs);
    }
    else
    {
        fprintf(stderr, "FEHLER: String enthält 8-Bit Zeichen - nicht codierbar\n");
        exit(1);
    }

    bitdump(septs);

    puts("");
    hexdump(octs);
    puts("");
    hexdump(septs);
    puts("");

    return 0;
}
Das eigentliche Geschehen spielt sich in oct2sep() ("Octet to Septet") ab.


Ich habe auch mal nach PDU-Konvertierprogrammen gegockelt. Die Beispielroutinen, die man so findet, drehen die Bits in der 7-Bit Darstellung zweimal auf links. Wozu das gut sein soll, kann ich nur raten.

Möglicherweise haben alle von einer Assembler-Beispielimplementierung abgeschrieben, die auf einem Prozessor implementiert wurde, der BITREV- (Bitreihenfolge in einem Byte umkehren) und ROTATE-Befehle (ähnlich wie SHIFT, aber ausgeschobene Bits links im Carry- und rechts im Zero-Flag halten) hat. Damit läßt sich eine elegante Routine implementieren, die per ROTATE Bits aus einem Byte raus und in das andere einschiebt (dazu muß auf einer Seite die Bitreihenfolge umgedreht werden, dann kommt man mit zwei 8-Bit Registern und dem Flag-/Statusregister aus).

In C bringt das keinen Vorteil (man kann weder Rotieren noch hat man Zugriff auf die Prozessor-Flags). Wenn Du's trotzdem probieren willst, kannst Du ja mal überlegen, wie Du in C die Bitreihenfolge in einem Byte umdrehen würdest...
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Onraku
Beiträge: 43
Registriert: Fr Sep 09, 2011 2:14 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von Onraku » Do Feb 13, 2014 6:38 pm

Ich hatte ja keine Ahnung wie SMS codiert werden. Sehr interessant das ist...
Ich höre den Thread schreien: er will ein Wiki-Artikel werden...

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von chris_1981_ » Fr Feb 14, 2014 9:08 pm

Hallo zusammen,

vielen Dank an alle, für die Unterstützung, ich finde es aber nicht gut, das es jetzt hier schon eine Lösung gibt, obwohl ich wirklich dankbar bin.
Ich habe die Lösung überflogen, aber nicht verstanden.
Ich würde gerne selber versuchen eine Möglichkeit zu erreichen, mein Vorhaben zu erledigen, auch wenn das für einen Anfänger wie mich, nicht wirklich leicht zu erreichen ist.

Nochmals, ich möchte nicht undankbar wirken / klingen, aber ich versuche mal Stück für Stück mein Glück und kann vielleicht zu diesem Thema nochmals Fragen stellen?

Vielen Dank!

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von mfro » Fr Feb 14, 2014 11:58 pm

chris_1981_ hat geschrieben: ...vielen Dank an alle, für die Unterstützung, ich finde es aber nicht gut, das es jetzt hier schon eine Lösung gibt, obwohl ich wirklich dankbar bin.
Ich habe die Lösung überflogen, aber nicht verstanden.
Ich würde gerne selber versuchen eine Möglichkeit zu erreichen, mein Vorhaben zu erledigen, auch wenn das für einen Anfänger wie mich, nicht wirklich leicht zu erreichen ist.
Tut mir leid, hoffentlich habe ich dir nicht den Spaß an der Sache verdorben. Natürlich wäre es am besten, wenn Du selbst eine Lösung erarbeitest.

Allerdings bin ich wirklich der Ansicht, daß das Problemchen für einen Anfänger tatsächlich ein bißchen zu anspruchsvoll ist.
Aber versuch's ruhig selbst - vielleicht unterschätze ich dich ja ;).

Fragen? Klar, nur zu.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von chris_1981_ » Sa Feb 15, 2014 1:54 pm

Hallo mfro,

ne du hast mir den Spaß nicht genommen, wobei? :-), nein, du gibst mir den nötigen Respekt für dieses Vorhaben.
Ich habe, bevor du deinen Code gepostet hast, noch nicht ganz den Umfang des ""Projekte"" überblickt, wie eigentlich immer ;-P.

Vor allem ärgere ich mich über mich selbst, damals nicht direkt mit C angefangen zu sein, stattdessen habe ich mit Bash, Shell und Perl Scripte angefangen.
Wenn ich das nicht getan hätte, wäre ich voraussichtlich heute schon in der Lage, diese Projekte besser umzusetzen.

Nochmals bitte nicht falsch verstehen, danke für deinen Code und vor allem für deine Mühe.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von mfro » Sa Feb 15, 2014 4:26 pm

chris_1981_ hat geschrieben: Vor allem ärgere ich mich über mich selbst, damals nicht direkt mit C angefangen zu sein, stattdessen habe ich mit Bash, Shell und Perl Scripte angefangen.
Genausowenig wie Schriftstellerei darin besteht, ein leeres weißes Blatt mit Worten zu füllen, ist Programmieren, Statements in einen Editor zu hacken. Beides ist nur der allerkleinste Teil der ganzen Sache.

Egal ob Du ein Buch oder ein Programm schreibst: die Hauptarbeit findet jeweils vorher im Kopf statt.

Beim Programmieren geht es darum, ein Problem zu verstehen, es in überschaubare, beherrschbare Einzelproblemchen zu zerlegen, jeweils eine Lösung dafür zu finden und sie anschließend in ein Programm zu packen. Erst ganz am Schluß schreibt man das Ergebnis auf. Kodieren ist wie Schreiben nur, seine Gedanken in Worte zu fassen.

Deswegen ist es meiner Ansicht nach (relativ) wurscht, in welcher Sprache das geschieht. Natürlich gibt es Sprachen, die für bestimmte Zwecke geeigneter sind (wie "im richtigen Leben": Liebesgedichte schreibt man ja anscheinend auch besser in Französisch ;) ), aber wenn man den grundsätzlichen Prozeß in einer Sprache beherrscht, kann man's - nach einer Weile Eingewöhnung - auch in einer anderen.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von chris_1981_ » Sa Feb 15, 2014 8:37 pm

hallo mfro,

da hast du wohl recht. Ärgere mich aber trotzdem über meine Situation, aber was solls, ich muss demnächst auch an Java beruflich ran... <kopfschüttel>

Warum in C? Na, wie auch im vorherigen Fall von mir geht es um µC.
Damit ich die "einzelnen Probleme" begreife und greifen kann, schreibe ich mir erst einmal nativ auf dem PC bevor ich an einen Mikrocontroller gehe.

ich melde mich hier wieder, sobald ich mal ein paar mehr Zeilen habe, die auch erkennbar machen das es voran geht.

Danke.

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von chris_1981_ » So Feb 16, 2014 12:07 pm

Hallo,

ich weiß, das passt nun einmal mal mehr nicht zum Thema, aber kann das sein,
dass der Aufbau der Kommunikation mit der seriellen Schnittstelle in C nicht so "einfach" ist als gedacht?
Da ich ein wenig auf andere Gedanken kommen wollte, habe ich mir gedacht, stelle dich mal der seriellen Datenkommunikation:

Vorerst noch der der Python Code zum auslesen der Schnittstelle:

Code: Alles auswählen

# define the serial
import serial
# modul
ser = serial.Serial('/dev/ttyUSB0', 19200)
Mir ist klar, hier hat Jemand Vorarbeit geleistet.

Jetzt mein Verständnis :-) für den C-Code.

Code: Alles auswählen

    FILE *input;
    input = fopen ("/dev/ttyUSB0","w");
    // Hier muss zwingend die Baudrate und die Stopbits 
    // definiert werden !!???

    if (NULL == input)
    {
        printf("NO Access to ttyUSB0 \n");
        exit (0);
    } 

    for (;;)
    {
        fprintf(input,"at^SRTC=0\r");

        sleep(2);
    }
}

So ähnlich hätte ich das nun auch unter Perl oder anderen Sprachen gemacht, wie oben zu sehen, aber hier bei dem Beispiel fehlt schon der Teil mit der Baudrate und dem Parity / Stop Bits. Hiermit funktioniert die Übertragung gar nicht.
Jetzt habe ich bei 'gockel' gesucht und bin fündig geworden...., wenn ich mir den nächsten Code so ansehen, stelle ich fest, warum in meinen C-Büchern darüber nicht so viel über dieses Thema drin steht:

Code: Alles auswählen

#include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        #include <termios.h>
        #include <stdio.h>

        /* baudrate settings are defined in <asm/termbits.h>, which is
        included by <termios.h> */
        #define BAUDRATE B19200            
        /* change this definition for the correct port */
        #define MODEMDEVICE "/dev/ttyUSB0"
        #define _POSIX_SOURCE 1 /* POSIX compliant source */

        #define FALSE 0
        #define TRUE 1

        volatile int STOP=FALSE; 

        main()
        {
          int fd,c, res;
          struct termios oldtio,newtio;
          char buf[255];
        /* 
          Open modem device for reading and writing and not as controlling tty
          because we don't want to get killed if linenoise sends CTRL-C.
        */
         fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
         if (fd <0) {perror(MODEMDEVICE); exit(-1); }
        
         tcgetattr(fd,&oldtio); /* save current serial port settings */
         bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */
        
        /* 
          BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
          CRTSCTS : output hardware flow control (only used if the cable has
                    all necessary lines. See sect. 7 of Serial-HOWTO)
          CS8     : 8n1 (8bit,no parity,1 stopbit)
          CLOCAL  : local connection, no modem contol
          CREAD   : enable receiving characters
        */
         newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
         
        /*
          IGNPAR  : ignore bytes with parity errors
          ICRNL   : map CR to NL (otherwise a CR input on the other computer
                    will not terminate input)
          otherwise make device raw (no other input processing)
        */
         newtio.c_iflag = IGNPAR | ICRNL;
         
        /*
         Raw output.
        */
         newtio.c_oflag = 0;
         
        /*
          ICANON  : enable canonical input
          disable all echo functionality, and don't send signals to calling program
        */
         newtio.c_lflag = ICANON;
         
        /* 
          initialize all control characters 
          default values can be found in /usr/include/termios.h, and are given
          in the comments, but we don't need them here
        */
         newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
         newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
         newtio.c_cc[VERASE]   = 0;     /* del */
         newtio.c_cc[VKILL]    = 0;     /* @ */
         newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
         newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
         newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
         newtio.c_cc[VSWTC]    = 0;     /* '\0' */
         newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
         newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
         newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
         newtio.c_cc[VEOL]     = 0;     /* '\0' */
         newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
         newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
         newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
         newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
         newtio.c_cc[VEOL2]    = 0;     /* '\0' */
        
        /* 
          now clean the modem line and activate the settings for the port
        */
         tcflush(fd, TCIFLUSH);
         tcsetattr(fd,TCSANOW,&newtio);
        
        /*
          terminal settings done, now handle input
          In this example, inputting a 'z' at the beginning of a line will 
          exit the program.
        */
         while (STOP==FALSE) {     /* loop until we have a terminating condition */
         /* read blocks program execution until a line terminating character is 
            input, even if more than 255 chars are input. If the number
            of characters read is smaller than the number of chars available,
            subsequent reads will return the remaining chars. res will be set
            to the actual number of characters actually read */
            res = read(fd,buf,255); 
            buf[res]=0;             /* set end of string, so we can printf */
            printf(":%s:%d\n", buf, res);
            if (buf[0]=='z') STOP=TRUE;
         }
         /* restore the old port settings */
         tcsetattr(fd,TCSANOW,&oldtio);
        }
der Code ist kopiert von Quelle: http://tldp.org/HOWTO/Serial-Programmin ... /x115.html 3.Chapter.

Wow! Der Code funktioniert, aktuell werden nur einzelne Zeichen ausgegeben.
Ganz schön aufwändig, oder liege ich da Falsch?

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Umwandlung von 8bit zu 7bit

Beitrag von cloidnerux » So Feb 16, 2014 1:46 pm

Wow! Der Code funktioniert, aktuell werden nur einzelne Zeichen ausgegeben.
Ganz schön aufwändig, oder liege ich da Falsch?
Die serielle Schnittstelle in C ist eine plackerei, keine Ahnung warum das so sein muss.
Ich habe mich mit Python oder C# abgefunden, es gibt aber auch ein QT Modul was das kann.
Redundanz macht wiederholen unnötig.
quod erat expectandum

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Umwandlung von 8bit zu 7bit

Beitrag von mfro » So Feb 16, 2014 2:51 pm

chris_1981_ hat geschrieben:...

Code: Alles auswählen

    FILE *input;
    input = fopen ("/dev/ttyUSB0","w");
...
    for (;;)
    {
        fprintf(input,"at^SRTC=0\r");

        sleep(2);
    }
}
...
Die stdio-Funktionen vergiß' mal für die serielle Schnittstelle gleich wieder. Die puffern und interpretieren I/O, da hast Du mehr Aufwand als es nutzt. Die serielle Schnittstelle bedient man besser eine Ebene drunter mit POSIX-kompatibler Funtktionalität (open(), close(), read(), write(), ...).

Wenn Du darauf achtest, keine Linux-spezifischen Funktionen zu nutzen, läuft dein Programm nicht nur dort, sondern auch auf Mac OS X und NT/Windows (und IRIX und Solaris und AIX, ...).

Das hier finde ich zur Orientierung nicht schlecht.

Tja, wenn man alles einstellen können will, heißt das eben auch, daß man alles einstellen muß ;). Das sollte dir aber nicht allzuviel ausmachen, dein Microcontroller will all die Einstellungen sicher auch und dort wirst Du alles für jede Microcontroller-Variante und -Hersteller neu schreiben müssen, weil es keine Standardisierung gibt.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Antworten