empfangene Daten der Seriellen Schnittstelle an Klasse mit Funktionszeiger übergeben.

jower

Mitglied
Hallo,
ich habe ein kleines Problemchen, das aus meiner Sicht auch nicht in anderen Forumsbeiträgen beehandelt wird.
ich habe eine Klasse, die eine Schnittstelle überwacht. Die Daten, die irgendwann empfangen werden, sollen weiterverarbeitet werden. jetzt möchte ich die Ververarbeitung in einer anderen Klasse machen, um die Schnittstelle gut zu kapseln und wiederverwendbar zu machen.
Nach ein wenig Recherche glaube ich, dass ein möglicher Ansatz der mit Funktionszeigern ist. Auch habe ich gehört,dass es gut sei, das Ganze auch über eine Managerklasse zu machen, die dann von der Schnittstellenklasse benachrichtigt wird, wenn Daten da sind und dann die Verarbeitungsklasse die Daten übergibt.
Meine Frage ist nun ob das der beste Ansatz ist oder ob es da nicht was viel schlaueres gibt und was bei meinem jetztigen Versuch mit Funktionszeiger falsch ist. Dazu hier der Code.
Die Seite http://www.newty.de/fpt/index.html hab ich mir auch schon angeguckt, scheint aber das ganze von der anderen Seite zu beschreiben (Kapitel 3.5), oder bin ich jetzt total verpeilt.

Die Klasse zu Überwachung der Schnittstelle. Die Daten werden nachdem sie empfangen werden in m_RecieveBuffer geschrieben. Die Daten und die Länge der Daten m_RecieveBufferSize will ich dann an die Funktion pt2Function irgendwie übergeben, die aus einer Managerklasse CManager stammt. hinter der pt2Function soll dann process stehen, das die Daten für CData::processdata bereitstellt.

Code:
class CPort{
public:
typedef void(*pt2Fn) (unsigned char* , unsigned long );

pt2Fn pDataReceived = 0;
void SetDataRecievedFnPointer(pt2Fn pt2Function){
    pDataReceived = pt2Function;
}

void DoDataRecieved(void){   
    if (pDataReceived)
        pDataReceived(m_RecieveBuffer, m_RecieveBufferSize);
}
private:
unsigned char *m_RecieveBuffer;
unsigned long m_RecieveBufferSize;
};

Code:
class CData{
public:
   void ProcessData(void);
};

Code:
class CManager{
public:
   void process(unsigned char* data, unsigned long length){ /*do the work here*/ };
private:
   CPort port;
   CData data;
};

Wäre schön, wenn sich jemand meldet, da ich mich irgendwie im Kreis drehe.
Vielleicht auch direkt am Beispiel, da ich sowas einfacher verstehe. Danke
 
Hallo jower,

die Lösung mit dem Funktionszeiger ist schon ganz gut. Der Code schaut auch soweit ganz ok aus. Da hast zwar nicht genau geschrieben, wo genau dein Problem liegt, aber ich vermute mal, der Compiler beschwert sich über den Aufruf von SetDataRecievedFnPointer(). Das läßt sich beheben, indem du den process()-member als "static" deklarierst. Wenn du ihn als "non-static" belassen willst, musst du etwas mehr Aufwand betreiben, das ist aber in dem von dir angegeben Link ganz gut beschrieben.

Eine andere Lösungsvariante wäre, eine Message an das Hauptfenster der Applikation zu schicken, und von dort die weitere Verarbeitung der Daten zu organisieren.
Ich habe den Weg mal kurz skizziert:

Code:
#define WM_RECEIVEDATA  WM_USER+100

in .h
-----

afx_msg LRESULT OnRunoutSignaling(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()

in .cpp
-------

BEGIN_MESSAGE_MAP(CBMainFrame, CFrameWnd)
    :
    :
    ON_MESSAGE(WM_RECEIVEDATA, OnReceivedData)
END_MESSAGE_MAP()

LRESULT CMainFrame::OnReceivedData(WPARAM wParam, LPARAM lParam)
{
    BYTE *pRecieveBuffer = (BYTE *)lParam;
    unsigned long lRecieveBufferSize = (unsigned long)wParam;

    // Auswertung
    return 0;
}   

in CPort
--------

void DoDataRecieved(void)
{   
    AfxGetMainWnd()->SendMessage(
        WM_RECEIVEDDATA, (WPARAM)m_RecieveBufferSize, (LPARAM)m_RecieveBuffer);
}
 
Re: empfangene Daten der Seriellen Schnittstelle an Klasse mit Funktionszeiger überge

ich schreibe das ganze erstmal als reine Konsolenanwendung, weil ich mich nicht mit dem ganzen MFC Kram verwirren will.
Das Sendmessage hab ich auch schon gesehen.
Genau das will ich ja ersetzen, da ich denke, dass MFC am Anfang zu sehr verwirrt.

Unter Kapitel 3.5 machen die das doch auch static, oder nicht?
Ich hätte nach dem Beispiel da eher gedacht, dass ich den SetDataReceived als static deklarieren müßte. Warum den process?

Ergänzung: Ich habe process jetzt als static deklariert und es funktioniert, hab wohl den Wald vor lauter Bäumen nicht gesehen. Danke für den Tip :)
 
Zuletzt bearbeitet:
Noch kurz zum Hintergrund: Aufrufkonventionen und Signaturen bei mittels Funktionspointern übergebenen Funktionen müssen den Regeln für normale C-Funktionen entsprechen. Das ist bei static-members der Fall, aber bei non-static-members sieht das aber ganz anders aus.
 
Re: empfangene Daten der Seriellen Schnittstelle an Klasse mit Funktionszeiger überge

ich hatte mich wohl zu früh gefreut,
die Funktion process kann ja leider nicht auf data zugreifen, da es sich ja um eine membervariable handelt. Mit dem Versuch data als parameter zu übergeben und dann zu casten komme ich auch nicht weiter, da man wohl Membervariablen nicht casten kann.
die Einzige Lölsung, die ich sehe, ist, die Funktion process nicht static zu haben, aber wie macht man das
hoffe mir kann einer helfen.
bis dann jower
 
Schnelle Lösung: Deklariere "data" ebenfalls als "static".
Ansonsten musst du dich wohl mal durch den Abschnitt 3.5 des "Function Pointer Tutorials" durcharbeiten.
 
Re: empfangene Daten der Seriellen Schnittstelle an Klasse mit Funktionszeiger überge

DAnke für die Idee data als static zu deklarieren. Nur geht das leider nicht, da ich data im Constructor CData::CData initialisiere und da sehe ich keine Möglichkeit da herum zu kommen.

Wenn ich mir das Beispiel unter 3.5 angucke, dann übergeben die der static Function pt2Function das Objekt, das dann innerhalb der Funktion auf ein neu erzeugtes Objekt gecastet wird. Dadurch kann man dann innerhalb einer static Funktin auf Instanzen zugreifen.
Genau das würde ich ja auch gerne machen, nur geht das eben nicht, dass ich MemberInstanzen als (void * ) caste und dann übergebe, weil man Membervariablen nicht casten kann.
Also ich glaub ich bin zu blöd und dafür hätte ich gerne eine Bestätigung ;)
Jower
 
Nach "Function Pointer Tutorial" Kapitel 3.5: Einfach einen Zeiger auf das Datenobjekt mit übergeben.
Die CPort-Klasse muss die Datenklasse gar nicht kennen, da ein void-Pointer übergeben wird.

Code:
class CBManager  
{
public:
    CBManager();
    virtual ~CBManager();

    static void process(void *pOb, BYTE *pData, unsigned long uiLen)
    {
        ((CData *)pOb)->ProcessData();
    }
    
    CPort m_port;
    CData m_data;
};

---------------------------------

class CPort  
{
public:
    CPort() { m_pDataReceived = NULL; }
    virtual ~CPort();

    pt2Fn  m_pDataReceived;
    void   *m_pOb;

    void SetDataRecievedFnPointer(pt2Fn pt2Function, void *pOb)
    {
        m_pDataReceived = pt2Function;
        m_pOb           = pOb;   
    }

    void DoDataRecieved()
    {   
        if( m_pDataReceived )
        {
            m_pDataReceived(m_pOb, m_RecieveBuffer, m_RecieveBufferSize);
        }
    }

private:
    unsigned char *m_RecieveBuffer;
    unsigned long  m_RecieveBufferSize;
};

---------------------------------

m_manager.m_port.SetDataRecievedFnPointer(m_manager.process, &m_manager.m_data);
 
Re: empfangene Daten der Seriellen Schnittstelle an Klasse mit Funktionszeiger überge

danke, ich hab´s letztendlich auch hingekriegt, genau wie Du es gemacht hast.
 
Zurück