Forum: Compiler & IDEs ARM-GCC FILE retarget


von Pascal H. (_pascal_)


Lesenswert?

Hi

ich moechte ein FreeRTOSserialStream implementieren.
Dazu habe ich ein unter Keil lauffaehiges Beispiel bekommen.

Dort wird das struct FILE neu definiert. Leider scheint das der ARM-GCC 
compiler nicht zu moegen.

Ich muss das tun um in meiner fputc eine referenz zum jeweiligen objekt 
zu haben.
1
int fputc(int ch, FILE *f)
2
{
3
4
  int ret = EOF;
5
6
  switch(f->handle)
7
  {
8
9
  case FREERTOS_STREAM_HANDLE:
10
11
    FreeRTOS_IOStream_Putch( (FreeRTOS_IOStreamHandle*)(f->devicePtr), (uint8_t)ch, portMAX_DELAY);
12
    ret = ch;
13
14
    break;
15
16
  case STDOUT_HANDLE:
17
  case STDERR_HANDLE:
18
  default :
19
20
    LPC_UART0->THR = ch;
21
    while (!(LPC_UART0->LSR & (1U << 5)));
22
23
    ret = ch;
24
25
    break;
26
27
  }
28
29
  return ret ;
30
31
}

Hier noch ein minimal Beispiel was nicht zu funktionieren scheint
1
#include <stdio.h>
2
3
struct __FILE
4
{
5
    int handle;
6
    void* devicePtr;
7
};
8
9
enum
10
{
11
    STDIN_HANDLE,
12
    STDOUT_HANDLE,
13
    STDERR_HANDLE,
14
    FREERTOS_STREAM_HANDLE,
15
    DISPLAY_OUT
16
};
17
18
int main(void) {
19
20
  FILE __stdin = {STDIN_HANDLE, 0};
21
  FILE __stdout = {STDOUT_HANDLE, 0};
22
  FILE __stderr = {STDERR_HANDLE, 0};
23
24
  while(1){
25
26
  }
27
28
}

Ich bekomme immer die warnung
"initialization makes pointer from integer without a cast"

Das passiert weil
1
FILE __stdin = {STDIN_HANDLE, 0};
STDIN_HANDLE ein integer ist aber im originalen struct FILE das erste 
argument ein "unsigned char *_p" ist.

Koennt ihr mir sagen warum das so in Keil funktioniert aber im ARM-GCC 
nicht? Was muss ich abaendern?

Gruss und Danke :)

von Karl H. (kbuchegg)


Lesenswert?

Pascal Heinrich schrieb:

> Koennt ihr mir sagen warum das so in Keil funktioniert aber im ARM-GCC
> nicht? Was muss ich abaendern?

Weil FILE eine 'private' Struktur der Implementierung ist und es eine 
ganze schlechte Idee ist, zu versuchen die neu zu definieren.

Denk dir was anderes aus, wie du den Klimmzug von einem FILE Pointer zu 
den Zusatzdaten die du brauchst, schaffst.
Du wandelst hier sowieso auf dünnem Eis. Denn diese Dinge sind extrem 
Implementierungsabhängig. Sprich, das macht sowieso jeder Compiler 
anders und du musst dir ansehen, welche Möglichkeiten dir der jeweilige 
Compiler/Run time System bietet. Das sind Dinge, in die man ohne 
zumindest rudimentär intime Kentnisse des vorgegebenen I/O Systems nicht 
eingreift. Ein Beispiel, das für einen anderen Compiler geschrieben 
wurde, kann dir höchstens zeigen, was eigentlich das Ziel wäre. Aber 
ansonsten kannst du da wenig damit anfangen. Der dahinter stehende 
Mechanismus kann völlig anders aussehen. Auf eine gcc für AVR 
funktioniert das zb völlig anders, wie man dem I/O System neue 
Funktionen für den Low-Level I/O Zugriff unterjubelt.

von Markus F. (mfro)


Lesenswert?

Ich muß vorausschicken, daß ich von FreeRTOS nur sehr rudimentäre 
Vorstellungen habe.

Dein Problem ist kein gcc-Problem, sondern ein Problem der verwendeten 
C-Library (was immer Du da hast, newlib?).

Völlig unabhängig davon: FILE umdefinieren zu wollen, ist 
höchstwahrscheinlich alles mögliche, bloß keine gute Idee (zumindest, 
wenn das I/O-Subsystem so funktioniert, wie ich mir das vorstelle).

Die Entwickler haben sich alle Mühe gegeben, FILE als opaque Struktur zu 
definieren, so daß sie "dahinter" treiben können, was sie wollen. 
Sprich: wie's da drin aussieht, geht dich nix an. Daran fummeln zu 
wollen, führt nur zu Problemen.

Wenn Du deiner C-Library einen neuen Gerätetyp unterjubeln willst (so 
habe ich deine Frage zumindest verstanden), solltest Du das eine Ebene 
"unter" stdio tun. Newlib beispielsweise stellt dazu als einheitliche 
Schnittstelle den devoptab_t Strukturtyp zur Verfügung, mit dem man der 
Library "I/O-Treiber" zur Verfügung stellen kann. Welche der Strukturen 
dann stdin, stdout und stderr bedient, wird dann der Library in einer 
struct __reent-Variable mitgeteilt, damit können unterschiedliche Tasks 
dann sogar unterschiedliche I/O-Treiber für die Standardkanäle benutzen.

von Pascal H. (_pascal_)


Lesenswert?

Danke fuer Eure Antworten :)

Ja das neu Definieren von FILE ist dann wahrscheinlich nicht die beste 
Idee. Der Keil compiler macht das anscheinend mit.

Im Grunde will ich eingeltich nur zum Zeitpunkt von "_write" eine 
Referenz zu einem bestimmten Output Kanal herstellen ( zB. UART0, UART1 
oder einer RTOS queue). Das wurde in dem Beispiel welches ich bekommen 
habe dadurch geloest FILE so umzudefinieren dass es eig gar kein FILE in 
dem Sinne mehr ist sondern einfach ein Struct mit einem int und einem 
void*.

Das mit dem reent und devoptab_t werde ich mir mal naeher ansehen 
muessen.

Als workaround habe ich im Moment einfach selbst Funktionen definiert 
(serialStreamPutc, serialStreamPuts, serialStreamGetc ...) welche ich 
mit einem von mir definierten FreeRtosStreamHandle aufrufen kann -> 
newlib printf usw wird gar nicht benutzt.

Jetzt habe ich aber noch eine Frage zur verwendeten C-Library.

Woher weis ich welche ich eigentlich benutze? Klar ich verwende den 
arm-none-eabi-gcc als compiler (toolchain). Wenn ich mir den Linker 
Command anschaue steht da nirgendwo etwas von einer libc.a oder 
irgendeiner anderen lib. Es werden nur meine .o Dateinen gelinkt.

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.