C++ template Funktion doppelt definiert in header und cpp

Gast #6864226
Lesenswert?

bei der Suche nach einem Problem in der Mbed SPI Funktion bin ich auf 
eine doppelte Definition einer Funktion gestossen. Es sieht für mich wie 
ein Fehler aus, der sich allerdings erstmal nicht auswirkt. Oder macht 
so etwas Sinn?
Ich kann auch den Code in SPI.cpp auskommentieren und es kompiliert und 
linkt ohne Fehler.

in SPI.h:
1
    template<typename Type>
2
    int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
3
    {
4
        if (spi_active(&_peripheral->spi)) {
5
            return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
6
        }
7
        start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
8
        return 0;
9
    }


und in SPI.cpp der gleiche Code, aber etwas andere Funktionssignatur:
1
int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event)
2
{
3
    if (spi_active(&_peripheral->spi)) {
4
        return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
5
    }
6
    start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
7
    return 0;
8
}
Gast #6864250
Lesenswert?

ja, danke, jetzt fällt der Grosche. Es gibt noch eine Deklaration die 
passt, nicht als template aber als Funktion:
1
    int transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event);

habe die Funktion jetzt so aufgerufen:
1
            // asynchronous transfer
2
            spi.transfer((const void*)tx_data, tx_word_len * sizeof(*tx_data),
3
                         (void*)rx_data, rx_word_len * sizeof(*rx_data), nullptr);

dann gibts natürlich Mecker wenn die Funktion fehlt.
Beim typisierten Bufferzeiger wird also die Größe automatisch richtig 
übergeben. Wenn man nicht blöderweise auf einen (char*) castet.
#6864291
Lesenswert?

Johannes S. schrieb:
> habe die Funktion jetzt so aufgerufen:            // asynchronous
> transfer
>             spi.transfer((const void*)tx_data, tx_word_len *
> sizeof(*tx_data),
>                          (void*)rx_data, rx_word_len * sizeof(*rx_data),
> nullptr);

Passt das irgendwie zum template?

Johannes S. schrieb:
> in SPI.h:    template<typename Type>
>     int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer,
> int rx_length, const event_callback_t &callback, int event =
> SPI_EVENT_COMPLETE)
>     {
>         ...
>     }
Gast #6864301
Lesenswert?

ich habe es aktualisiert, ist nicht wie es zuerst oben stand:
1
        tx_word_len = 2;
2
        rx_word_len = 2;
3

4
    const uint16_t tx_data[8] = {0x1122, 0x3344}; // allocate extra memory to prevent "out of range" error
5
    uint16_t rx_data[8] = {0};
6

7
            spi.transfer(tx_data, tx_word_len * sizeof(*tx_data),
8
                         rx_data, rx_word_len * sizeof(*rx_data), nullptr);

das ist Teil von einem Testcode, deshalb die 'komische' Größenangabe.
Gast #6864358
Lesenswert?

es funktioniert nicht, zumindest nicht mit einem H7, deshalb suche ich 
da, aber die Ursache muss eine andere sein.
Trotz 4 Augen hatte ich die zweite Deklaration im Header übersehen, habe 
da schon zu lange draufgestarrt.

der callback ist das 5. Argument in der template Funktion, der ist jetzt 
der nullptr und wird damit nicht aufgerufen. Das 6. ist ein event, das 
wird dem callback mitgegeben und ist default und uninteressant wenn der 
callback nicht aufgerufen wird.

Mit der Funktion im Header kommt der Debugger nicht gut klar, der hat 
mich da auch verwirrt.

Und das eigentliche Problem ist das SPI beim H7 das jetzt noch zickt. 
Jemand hatte den SPI Code angepackt und ein andere Problem beseitigt. 
Damit funktionierte aber SPI mit 16 Bit nicht mehr. Das konnte ich jetzt 
für STM32F4 beheben, aber der Test mit dem H7 zeigte wieder neue 
Probleme. Im H7 ist ein komplett neues SPI Device, das versteht man 
glaube ich nur wenn man das gleiche raucht wie die Entwickler.

Hoffe ich konnte genug verwirren und Danke nochmal für die Anteilnahme 
:)
#6869069
Lesenswert?

Johannes S. schrieb:
> der callback ist das 5. Argument in der template Funktion, der ist jetzt
> der nullptr und wird damit nicht aufgerufen.

Irgendwie fehlt noch etwas an der Geschichte...

Das callback ist doch als Referenz deklariert in der Parameterliste.
Wie kann man für eine Referenz einen nullptr übergeben?

Ich glaube nach wie vor, daß du was ganz anderes aufrufst, was du uns 
noch nicht gezeigt hast.
Gast #6869083
Lesenswert?

Blume schrieb:
> Mit welchem H7 Board aebeitet ihr denn?

ich benutze dieses:
https://de.aliexpress.com/item/1005001683272407.html
war aber von einem anderen Händler.
sehe gerade 11000+ verfügbar, gute Quelle für die H743 :)

Klaus W. schrieb:
> Das callback ist doch als Referenz deklariert in der Parameterliste.
> Wie kann man für eine Referenz einen nullptr übergeben?

doch hat definitv funktioniert mit nullptr ohne Compilermecker, habe 
jetzt aber auch mal eine Funktion angegeben.
https://github.com/JojoS62/testSPI/commits/master/main.cpp
in dem commit davor ist noch der nullptr drin.

Das SPI Problem nach dem ich suchte war aber ein anderes, das SPI device 
im H7 und U5 ist ein anderes, neues als bei den älteren Serien. Das hat 
u.a. ein 'lock' feature, d.h. einige Einstellungen wie Direction lassen 
sich nicht ändern wenn SPI enabled ist. Da kann man herrlich nach 
Fehlern suchen.
Gast #6869126
Lesenswert?

was mache ich dann falsch?
Das wird in der Callback Klasse gehandhabt, fragt mich nicht wie. Ich 
bin froh das ich mittlerweile einen Callback benutzen kann, die 
Implementierung ist schon hardcore, da wurde schon ein paar Tage dran 
gearbeitet:
https://github.com/ARMmbed/mbed-os/blob/master/platform/include/platform/Callback.h

beim Aufruf eines Callback muss man auf ungleich nullptr prüfen, das 
wird hier auch gemacht:
1
    if (_callback && (event & SPI_EVENT_ALL)) {
2
        _set_ssel(1);
3
        unlock_deep_sleep();
4
        _callback.call(event & SPI_EVENT_ALL);
5
    }

Ich denke es funktioniert so: der nullptr ist keine Klasse 
event_callback_t und durch
1
using event_callback_t = Callback<void(int)>;
wird implizit eine Instanz Callback(nullptr) erzeugt, die ist definiert 
und damit dann auch eine gültige Referenz. Ist das so richtig?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren