#ifndef VMODICAN_H
#define VMODICAN_H

#include <pthread.h>

#include "unistd.h"          // gettimeofday

#include "log.h"
#include "gendef.h"

class VmodIcan : public Log
{
private:
    int fd; // file descriptor for can module
    pthread_t *fRxThrd;

    int Ioctl(int msg, void *arg);

    static void *ReceiveThread(void *data);

    void HandleMessage(Message *msg, struct timeval *tv);
    virtual void HandleCanMessage(WORD_t cobid, BYTE_t *data, struct timeval *tv) {}

    int Receive(Message *pm);
    int ReceiveFast(FastMessage *pm);

    void SetBaudRate(int rate);
    void EnableCanBusConnection();
    int  EnableFastCan(int rbuffers, int wbuffers);
    void DisableCanBusConnection();
    int  EnableFifo();
    int  Reset();
    void SetTermination(int strate=1);
    int  StdHost2NewStyle(int rbuffers, int wbuffers, int wbuffers_hi, int wbuffers_low);
    void DisableAllCobIds();

    void PrintMsg(Message *m);

    int Send(Message *pm);
    int SendHi(Message   *pm);
    int SendLo(Message   *pm);
    int Send(FastMessage *pm);

    void Close();
    int Open(const char *devname);          /* pathname of device */

    WORD_t MsgDescr(const WORD_t cobid, const BYTE_t dlc, const BYTE_t rtr=0)
    {
        return (cobid<<5) | ((rtr&0x1)<<4) | (dlc&0xf);
    }

    virtual void TerminateApp() { exit(-1); }

protected:
    void StartReceiver();
    void StopReceiver();

public:
    VmodIcan(const char *dev, const int baud, ostream &out=cout);
    virtual ~VmodIcan();

    void EnableCobId(WORD_t cobid, int flag=TRUE);

    void SendCanFrame(WORD_t cobid, BYTE_t m[8]);
    void SendCanFrame(WORD_t cobid,
                      BYTE_t m0=0, BYTE_t m1=0, BYTE_t m2=0, BYTE_t m3=0,
                      BYTE_t m4=0, BYTE_t m5=0, BYTE_t m6=0, BYTE_t m7=0);
};

#endif
