Forum: Compiler & IDEs Strings zur Compilezeit in ein ByteArray einfügen (und auffüllen)


von Philipp D. (phili)


Lesenswert?

Liebe Leute,
ich möchte im Programmspeicher ein Bytearray ablegen, welches ich zur 
Compilezeit "zusammenstelle". Dazu habe ich einige #defines erstelle, 
über die die die Feldinhalte festlege:
1
#define NMEA2000_NMEADATABASEVERSION  1210        //  2Byte
2
#define NMEA2000_MFPRODUCTCODE    61258       //  2Byte
3
#define NMEA2000_MFMODELID    "Meine ID"  // 32Byte ASCII

Zur Compilezeit soll dann alles zusammengesetzt werden:
1
const prog_uint8_t NMEA2000_ProductInformation_Data[] = {
2
  (uint8_t)(NMEA2000_NMEADATABASEVERSION),
3
  (NMEA2000_NMEADATABASEVERSION>>8),
4
  (uint8_t)(NMEA2000_MFPRODUCTCODE),
5
  // hier soll jetzt das "Char-Array" eingefügt werden
6
  // und dann kommen noch weitere Bytes und Words ....
7
};

Das klappt auch bis auf den String "NMEA2000_MFMODELID". Hier weiß ich 
nicht, wie ich den zur Compilezeit geeignet zerlegen lassen kann, so 
dass die einzelnen Buchtaben sukkzessive in den Bytes von 
"NMEA2000_ProductInformation_Data" abgelegt werden.

Außerdem ist in der Spezifikation vorgeschrieben, das 
"NMEA2000_MFMODELID" 32 Byte lang zu sein hat und alle nicht vewendeten 
Bytes mit 0xFF aufgefüllt werden. Kann mann das auch irgendwie geschickt 
mit Präprozessor und Compiler lösen?

Ich hätte gern den fertigen Datensatz im Flash, damit ich im Programm 
dann nurnoch die Daten kopieren muss.

lG Phili

von Sven P. (Gast)


Lesenswert?

Philipp Drewes schrieb:
>
1
> const prog_uint8_t NMEA2000_ProductInformation_Data[] = {
2
>   (uint8_t)(NMEA2000_NMEADATABASEVERSION),
3
>   (NMEA2000_NMEADATABASEVERSION>>8),
4
>   (uint8_t)(NMEA2000_MFPRODUCTCODE),
5
>   // hier soll jetzt das "Char-Array" eingefügt werden
6
>   // und dann kommen noch weitere Bytes und Words ....
7
> };
8
>
>
> Das klappt auch bis auf den String "NMEA2000_MFMODELID".
Das klappt auch mit dem Rest nicht.

Wenn du NMEA2000_NMEADATABASEVERSION auf uint8_t castest, wird der Rest 
(obere 8 Bits) abgeschnitten und du hast nen falschen Wert drin.

von Philipp D. (phili)


Lesenswert?

Hallo Sven,
danke für Deine Antwort.

>> Das klappt auch bis auf den String "NMEA2000_MFMODELID".
> Das klappt auch mit dem Rest nicht.
>
> Wenn du NMEA2000_NMEADATABASEVERSION auf uint8_t castest, wird der Rest
> (obere 8 Bits) abgeschnitten und du hast nen falschen Wert drin.

Mein System erwartet die Daten im Little-Endian Format. Somit müssen die 
Daten für das Byte 0 abgeschnitten werden. Für Byte 1 wird geeignet 
geshiftet.

Hast Du eine Idee für den String?
Geht das überhaupt so?

Phili

von Klaus W. (mfgkw)


Lesenswert?

vielleicht sollte es so ähnlich aussehen:
1
#define NMEA2000_NMEADATABASEVERSION   1210        //  2Byte
2
#define NMEA2000_MFPRODUCTCODE        61258        //  2Byte
3
#define NMEA2000_MFMODELID            "Meine ID"                          \
4
                                      "\xff\xff\xff\xff\xff\xff\xff\xff"  \
5
                                      "\xff\xff\xff\xff\xff\xff\xff\xff"  \
6
                                      "\xff\xff\xff\xff\xff\xff\xff\xff"
7
8
const struct
9
{
10
  prog_uint16_t databaseversion;
11
  prog_uint16_t productcode;
12
  prog_uint8_t  modelid[32];
13
}
14
  NMEA2000_ProductInformation_Data  =
15
    {
16
      NMEA2000_NMEADATABASEVERSION,
17
      NMEA2000_MFPRODUCTCODE,
18
      NMEA2000_MFMODELID
19
    };

(bzw. die beiden 16-Bitwerte in je 8 Bit aufgeteilt und getrennt 
initalisiert mit cast bzw. Shift, wenn es sonst mit der Reihhenfolge
kneift)

von Sven P. (Gast)


Lesenswert?

Da wäre ich vorsichtig, die Schieberei und so wird m.W.n. arithmetisch 
durchgeführt. Schreibs lieber explizit dazu.

Ein Stringliteral à la "blablabla" zerfällt normalerweise in einen 
Zeiger. Lediglich im Kontext einer Vektorinitialisierung zerfällts in 
einzelne Zeichen:
1
char vektor[] = "abc";

Ich wüsste jetzt nicht, wie man dein Problem ohne gescheite Strukturen 
so lösen könnte :-(

von Philipp D. (phili)


Lesenswert?

Hallo ihr beiden,

vielen Dank für die Hinweise. So lässt es sich realisieren.

lG Phili

von Klaus W. (mfgkw)


Lesenswert?

ach und noch ein Tipp:

falls die ID von Fall zu Fall unterschiedlich lang ist, kann
man auch einfach soviele \xFF zum Auffüllen nehmen, daß es
auch für eine kurze ID sicher reicht (also am sichersten 32 hier).

Das erzeugt dann zwar eine Warnung, ist sonst aber nicht weiter 
schädlich.

Der Compiler weiß ja, daß das Feld nur 32 Byte hat und ignoriert
die überzähligen Bytes der Initialisierung.

von Klaus F. (kfalser)


Lesenswert?

Warum eigentlich mit 0xFF auffüllen?
Bei einem String wird laut C immer ein 0x00 angehängt.
Die Initialisierung eines character Feldes kann auch kürzer sein, nur 
das abschließende 0x00 wird von C gebraucht.

von Philipp D. (phili)


Lesenswert?

Klaus Falser schrieb:
> Warum eigentlich mit 0xFF auffüllen?
> Bei einem String wird laut C immer ein 0x00 angehängt.
> Die Initialisierung eines character Feldes kann auch kürzer sein, nur
> das abschließende 0x00 wird von C gebraucht.

Hallo Klaus,
die Daten werden über einen CAN-Bus versendet. Die Spezifikation des 
verwendeten Protokolls erwartet, dass mit 0xFF aufgefüllt wird

von Philipp D. (phili)


Lesenswert?

Klaus Wachtler schrieb:
> ach und noch ein Tipp:
>
> falls die ID von Fall zu Fall unterschiedlich lang ist, kann
> man auch einfach soviele \xFF zum Auffüllen nehmen, daß es
> auch für eine kurze ID sicher reicht (also am sichersten 32 hier).
>
> Das erzeugt dann zwar eine Warnung, ist sonst aber nicht weiter
> schädlich.
>
> Der Compiler weiß ja, daß das Feld nur 32 Byte hat und ignoriert
> die überzähligen Bytes der Initialisierung.

Und noch eine weitere Anmerkung / Frage hierzu. Damit die Strings auch 
im Flash landen, muss das folgende Vorgehen verfolgt werden:

Beitrag "[AVR-GCC] struct-Initialisierung. PROGMEM und Strings"

Da ich dann im Struct ja aber den Pointer habe, muss ich die Länge von 
32 Byte direkt in der String-Definition vorgeben. Hier der aktuelle 
Code-Ausschnitt
1
typedef struct {
2
  uint16_t    databaseversion;
3
  uint16_t    productcode;
4
  const char  *pmodelid;
5
  const char  *psoftwareversion;
6
  const char  *pmodelversion;
7
  const char  *pmodelserialcode;
8
  uint8_t     certificationlevel;
9
  uint8_t     loadequivalancy;  
10
} tNMEA2000_ProductInformation;
11
12
const char PROGMEM modelid[32] = NMEA2000_MODELID;
13
const char PROGMEM softwareversion[32] = NMEA2000_SOFTWAREVERSIONCODE;
14
const char PROGMEM modelversion[32] = NMEA2000_MODELVERSION;
15
const char PROGMEM modelserialcode[32] = NMEA2000_MODELSERIALCODE;
16
17
const tNMEA2000_ProductInformation PROGMEM NMEA2000_ProductInformation = {
18
    NMEA2000_DATABASEVERSION,
19
    NMEA2000_PRODUCTCODE,
20
    modelid,    
21
    softwareversion,
22
    modelversion,
23
    modelserialcode,
24
    NMEA2000_CERTIFICATIONLEVEL,
25
    NMEA2000_LOADEQUIVALENCY
26
};

von Philipp D. (phili)


Lesenswert?

Und dann ergibt sich damit das Problem, dass ich auf die uints mit Hilfe 
der "pgm_read_xxx"-Routinen zugreifen kann. Für die Strings benötige ich 
aber "geschachtelte" "pgm_read_word" und "pgm_read_char" Routinen um 
erst die Start-Adresse des Strings zu holen und dann den Inhalt lesen zu 
können.

Ich meiner Implementation würde ich später aber gern nur mit "memcpy_P" 
arbeiten und keine weiteren "i"-angängigen Entscheidungen treffen.
Hier ein Code-Ausschnitt.
1
for (uint8_t i=0; i<18; i++){
2
    message.data[0] = fast_packet_index++;
3
    memcpy_P(message.data+1, &NMEA2000_ClaimAddress+6+7*i, 7);
4
    mcp2515_send_message(&message);
5
}

Meine Frage ist also weiterhin:
Wie erhalte ich eine sequentielle Datenstruktur im Flash, die aus 
unsigned Integers verschiedener Größe und mehreren Strings besteht, zur 
Compilezeit zusammengebaut wird und später sukzessive mit Hilfe von 
"memcpy_P" gelesen werden kann??

Danke noch einmal für alle bisherigen Vorschläge, Nachfragen und 
Anregungen!!

Euer Phili

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.