#include "avddriverudp.h"

#include <QUdpSocket>
#include <QNetworkDatagram>
#include <QThread>

//#include "qgrexrtgsocket.h"
#include "qgnetworkinterface.h"

#include "qgscopechrono.h"

#include <QSettings>

#include <QLocalServer>
#include <QLocalSocket>

enum Avb1553UdpPort
{
    rt_port=51553,
    bc_port=61553
};

enum
{
    mon_max_msg=512
};

#include "udp1553_types.h"


#if 0
struct udp_1553_header_t
{
    uint16_t marker1553;
    uint16_t frame_counter;
    uint32_t ttag;
    uint32_t discretes_in;
    uint32_t discretes_out;
};

struct upd_1553_msg_t
{
    uint16_t ctrl;
    uint16_t cw;
    uint16_t sw;
    uint16_t spare;
    uint16_t timetag[2];
};

#endif

struct ctrl_info_t
{
    udp_1553_msg_t* ctrl;
    uint16_t* payload;
    int frq;
    int frq_coundown;
    unsigned int conditional;
    unsigned int skip_words;
    avb_1553_bc_message_t* handler;
};



struct device_data_t
{
    avb_1553_bc_frame_t bc_frame;
    int bc_frame_pos;

    avb_1553_monitor_isr_t mon_isr;
    avb_1553_major_frame_handler_t beginHandler;
    avb_1553_major_frame_handler_t majorHandler;
    avb_1553_major_frame_handler_t minorHandler;
    avb_1553_major_frame_handler_t eofHandler;

    //uint16_t mcRxDataWord[32];
    //uint16_t mcTxDataWord[32];
    ctrl_info_t ctrl_info[2][32];

    uint16_t buffersRxTx[3][32][32];

    //uint32_t mcWords[32];

    //avb_1553_bc_message_t* bcHandlers[2][32];

    uint16_t bcPreparedMsg[1500];
    unsigned int bcPreparedSize;

    avb_1553_intr_status_t ists;

    IAvbDriver::run_status_t run_sts;

    avb_1553_bc_frame_t frameDescriptor;

    struct {
        avb_1553_monitor_info_t info;
        avb_1553_mon_decoded_t msg[mon_max_msg];
    } mon;

    bool skip_next_enabled;

    int rtUnknown;
};

static device_data_t dd;

static unsigned long long tt_base;

#define BC_MINOR_FRAME_NICE    1

class AvbDriverUDP::AvbUdpImplemenation
{
public:
    QThread thread;

    QUdpSocket s;
    AvbDriverUDP* sd;

    QHostAddress tgtHost;
    QHostAddress ha;
    bool bc_connected;
    bool bc_running;

    uint16_t raw[32];

    unsigned int frame_counter;

    QLocalServer* server;
    QLocalSocket* remoteSocket;

    AvbUdpImplemenation()
    {
        frame_counter=0;
        bc_connected=false;
        remoteSocket=0;
    }

    int updateDatagram()
    {
        static unsigned int mcounter;

        memset(dd.bcPreparedMsg, 0, sizeof dd.bcPreparedMsg);

        int eof=0;
        udp_1553_header_t* hh=reinterpret_cast<udp_1553_header_t*>(dd.bcPreparedMsg);
        uint16_t* raw=(uint16_t*)&hh[1];

        hh->marker1553=udp_1553_header_t::k_marker_1553;
        hh->otype=udp_1553_header_t::k_otype_bc;
        hh->vmajor=0;
        hh->vminor=0;
        hh->ta=0;
        hh->flags=0;
        hh->fcounter=frame_counter;
        //hh->flags_ext=0;

        if (dd.bc_frame_pos>=dd.bc_frame.num_of_message)
        {
            dd.bc_frame_pos=0;
            ++dd.ists.major_frames;
            eof=1;
        }
        int k=0;

        dd.bcPreparedSize=sizeof *hh;

        unsigned long now=sd->chronoTimer().timeNow();
        hh->ltt=now;

        avb_1553_bc_message_t** table=dd.bc_frame.msg;

        int minor_compression=1;

        bool skip_next=false;

        int n_out=0;

        for(; dd.bc_frame_pos<dd.bc_frame.num_of_message; ++dd.bc_frame_pos)
        {
            const avb_1553_bc_message_t* m=table[dd.bc_frame_pos];
            if (m==0)
            {
                eof=1;
                dd.bc_frame_pos=0;
                break;
            }
            if (m->msg==avb_frame_end_of_minor)
            {
                --minor_compression;
                if (minor_compression<=0)
                {
                    ++dd.bc_frame_pos;
                    eof=2;
                    break;
                }
                continue;
            }
            if (m->msg==avb_frame_end_of_major)
            {
                eof=1;
                dd.bc_frame_pos=0;
                ++frame_counter;
                break;
            }
            if (m->msg->type==avb_t_nop)
                continue;
            if ((m->msg==avb_frame_skip_next_message) || (m->msg->type==avb_t_nop_skip_next))
            {
                if (dd.skip_next_enabled)
                    skip_next=true;
                    continue;
            }
            if (skip_next)
            {
                skip_next=false;
                continue;
            }
            if (m->msg->target->adr!=20)
                continue;

            ++n_out;

            udp_1553_msg_t* u=(udp_1553_msg_t*)&raw[k];
            u->marker=udp_1553_header_t::k_ctrl_marker_begin;
            avb_1553_cmd_word_t cw;
            cw.raw=0;
            cw.str.rt=m->msg->target->adr;
            cw.str.sa=m->msg->sa;
            cw.str.wc=m->msg->wc;
            cw.str.tr=m->msg->tr;
            u->cw=cw.raw;
            u->sw=0;
            u->errcode=0;
            k+=(sizeof *u)/2;

            if (m->msg->tr==0)
            {
                uint16_t* tmp=(uint16_t*)&u[1];
                if ((m->msg->sa==0) || (m->msg->sa==31))
                {
                    tmp[0]=dd.buffersRxTx[m->msg->tr][m->msg->sa][0];
                    ++k;
                }
                else
                {
                    memcpy(&u[1], dd.buffersRxTx[m->msg->tr][m->msg->sa], m->msg->wc*2);
                    k+=m->msg->wc;
                }
                //qDebug()<<"***MSG:"<<cw.raw<<m->msg->wc<<tmp[0]<<dd.buffersRxTx[m->msg->tr][m->msg->sa][0];
            }
            raw[k]=~cw.raw;
            raw[k+1]=udp_1553_header_t::k_ctrl_marker_end;

            k+=2;
            //u->timetag[0]=now;
            //unsigned int wc=((m->msg->sa==0) || (m->msg->sa==31)) ? 1 : m->msg->wc;
        }

        hh->mcounter=mcounter;
        raw[k]=udp_1553_header_t::k_marker_end_1553;
        ++k;

        if (n_out)
        {
            dd.bcPreparedSize+=k*2;
            ++mcounter;
        }
        else
            dd.bcPreparedSize=0;

        return eof;
    }

    void bcFrameGenerator()
    {
        if (!sd->deviceActive())
        {
            bc_running=false;
            return;
        }

        if ((dd.run_sts!=IAvbDriver::sts_bc_run) && (dd.run_sts!=IAvbDriver::sts_bc_mon_run))
            return;
        if (dd.bc_frame.num_of_message==0)
            return;

        bc_running=true;

        unsigned long long ttag=sd->chronoTimer().timeNow();

        if (dd.bc_frame_pos==0)
        {
            tt_base=ttag;
            dd.ists.major_frame_tt=ttag;
            ++dd.ists.major_frames;
            if (dd.beginHandler)
                dd.beginHandler(sd, dd.ists.major_frames, ttag);
        }

        int sts=updateDatagram();

        if (dd.bcPreparedSize)
        {
            //qDebug()<<"UDP1553:"<<tgtHost<<dd.bcPreparedSize;
            s.writeDatagram((char*)dd.bcPreparedMsg, dd.bcPreparedSize, tgtHost, rt_port);

            //uint16_t* p=&dd.bcPreparedMsg[(sizeof(udp_1553_header_t))/2];
            //processMsg(p, (dd.bcPreparedSize-sizeof(udp_1553_header_t))/2, true);
            processMsg(dd.bcPreparedMsg, dd.bcPreparedSize, true);
        }

        ++dd.ists.raised;

        {
            if (sts==2 && dd.minorHandler)
            {
                dd.minorHandler(sd, dd.ists.major_frames, ttag);
            }
            if (sts==1 && dd.majorHandler)
                dd.majorHandler(sd, dd.ists.major_frames, ttag);
        }
    }

    void bcReceive()
    {
        while (s.hasPendingDatagrams())
        {
            QNetworkDatagram d=s.receiveDatagram();
            QByteArray data=d.data();

            const udp_1553_header_t* h=reinterpret_cast<const udp_1553_header_t*>(data.constData());
            if ((h->marker1553!=udp_1553_header_t::k_marker_1553)) // && d.senderPort()==rt_port)
                return;
            tgtHost=d.senderAddress();  //bind ot host. This doen't support multiple RT
            int mf_time=dd.bc_frame.minor_frame_time*BC_MINOR_FRAME_NICE;
            if ((!bc_connected) || (sd->chronoTimer().period()>(mf_time)))
            {
                bc_connected=true;
                qDebug()<<"AvbUDP:"<<mf_time;

                sd->chronoTimer().start(mf_time);
            }
            unsigned int size=data.size();
            uint16_t* p=(uint16_t*)&h[0];
            //size=size-sizeof(udp_1553_header_t);
            //size=size>>1;
            processMsg(p, size, false);

            if (remoteSocket && remoteSocket->isValid())
            {
                remoteSocket->write(data);
            }

        }
    }

    void processMsg(const uint16_t* raw, unsigned int size, bool bc_tx=false)
    {
        //decode
        unsigned long long ttag=sd->chronoTimer().timeNow();

        const uint16_t* p=&raw[(sizeof(udp_1553_header_t))/2];
        unsigned int msg_size=(size-sizeof(udp_1553_header_t));
        msg_size=msg_size/1;

        const udp_1553_header_t* hdr=(udp_1553_header_t*)raw;
        if (hdr->marker1553!=udp_1553_header_t::k_marker_1553)
        {
            qDebug()<<"??? Invalid header";
            return;
        }
        unsigned int n=0;

        for(unsigned int i=0; i<msg_size;)
        {
            const udp_1553_msg_t* h=(const udp_1553_msg_t*)&p[i];

            if (h->marker==udp_1553_header_t::k_marker_end_1553)
            {
                //qDebug()<<"UDP: END"<<i<<msg_size;
                break;
            }
            if (h->marker!=udp_1553_header_t::k_ctrl_marker_begin)
            {
                qDebug()<<"UDP: inv begin marker"<<bc_tx<<h->marker;
                break;
            }
            //uint16_t ctrl=h->marker;
            avb_1553_cmd_word_t cw;
            cw.raw=h->cw;
            avb_1553_sts_word_t sw;
            sw.raw=h->sw;

            if (cw.raw==0)
            {
                qDebug()<<"UDP: null cw";
                return;
            }

            ++n;
            uint16_t wc=cw.str.wc;
            uint16_t sa=cw.str.sa;
            uint16_t rt=cw.str.rt;
            int rxtx=cw.str.tr;

            if ((wc==0) || (wc>32))
                wc=32;
            if ((sa==0) || (sa==31))
                    wc=0;

            const uint16_t* payload=(const uint16_t*)&h[1];

            bool process=bc_running && (rxtx==0) && bc_tx;
            process=process || ((rxtx==1) && (bc_tx==false));

            if (!process)
                wc=0;

            if (bc_tx==false)
            {
                //qDebug()<<"UDP:"<<process<<rt<<sa<<rxtx<<wc;
            }

            bool add_to_mon=(!bc_running) || process;

            //if (ctrl==0)
            {
                ctrl_info_t* ctrl=&dd.ctrl_info[rxtx][sa];

                if (process)
                {
                    if (rt!=20)
                    {
                        ++dd.rtUnknown;
                        qDebug()<<"UDP: unknown"<<rt;
                    }
                    if (!h->errcode)
                        memcpy(dd.buffersRxTx[rxtx][sa], payload, wc*2);

                    avb_1553_bc_message_t* hm=ctrl->handler; //dd.bcHandlers[rxtx][sa];
                    if (hm)
                    {
                        hm->msg->buffer=(avb_1553_data_buffer_t*)dd.buffersRxTx[rxtx][sa];

                        if (hm->msg->msgHandler)
                        {
                            hm->msg->msgHandler(sd, true, hm->msg, ttag);
                        }
                    }
                }
                unsigned int counter=dd.mon.info.total_message;

                if (process && add_to_mon && (counter<mon_max_msg))
                {
                    avb_1553_mon_decoded_t& mmsg=dd.mon.msg[counter];
                    mmsg.bit_in_status_err=sw.str.me;
                    mmsg.broadcast=(cw.str.rt==0) || (cw.str.rt==31);
                    mmsg.bus=0;
                    mmsg.cmd=cw;
                    mmsg.sts=sw;
                    mmsg.sa=cw.str.sa;
                    mmsg.err=false;
                    mmsg.internal_eror_code=0;
                    mmsg.invalid=false;
                    mmsg.modecode=(cw.str.sa==0) || (cw.str.sa==31);
                    mmsg.no_response=false;
                    memcpy(mmsg.data, payload, wc*2);
                    mmsg.wc=wc;
                    mmsg.rt=rt;
                    mmsg.rx_sts_received=true;
                    mmsg.rtrt_tx_cmd.raw=0;
                    mmsg.rtrt_tx_sts.raw=sw.raw;
                    mmsg.next=0;
                    mmsg.timetag=ttag;
                    ++dd.mon.info.total_message;
                    if (dd.mon.info.total_message>mon_max_msg/2)
                    {
                       dd.mon.info.buffer=(avb_1553_word_t*)dd.mon.msg;
                       if (dd.mon_isr)
                            dd.mon_isr(&dd.mon.info);
                    }
                }
                if (!h->errcode)
                    i+=wc;
                i+=((sizeof(udp_1553_msg_t))/2);

                unsigned int ii=i;
                i+=2;


                uint16_t cw_not=~h->cw;
                if (p[ii]!=cw_not)
                {
                    qDebug()<<"UDP: inv ~CW"<<hdr->mcounter<<n<<p[ii]<<bc_tx<<wc<<h->cw;
                    continue;
                }
                if (p[ii+1]!=udp_1553_header_t::k_ctrl_marker_end)
                {
                    qDebug()<<"UDP: inv end marker"<<hdr->mcounter<<n<<bc_tx<<wc<<p[ii+1];
                    continue;
                }
            }
        }
    }
};

AvbDriverUDP::AvbDriverUDP(const QHostAddress *ha):
    QgScopeDevice("AbdDriverUDP.grifo", "AVB1553UDP"),
    p_(*new AvbUdpImplemenation)
{
    p_.tgtHost=QgNetworkInterface::networkBroadcast();

    if (ha)
    {
        if (!ha->isNull())
        {
            p_.ha=*ha;
            if (!ha->isLoopback())
            {
                quint32 ip=ha->toIPv4Address();
                ip|=255;
                p_.tgtHost=QHostAddress(ip);
            }
            qDebug()<<"***UDP1553:"<<p_.ha<<p_.tgtHost;
        }
    }

    p_.sd=this;
    //p_.s.bind(QgRexNetwork().networkInterface(), bc_port);
    p_.bc_connected=false;

    this->moveToThread(&p_.thread);
    this->p_.sd->moveToThread(&p_.thread);
    this->p_.sd->chronoTimer().moveToThread(&p_.thread);

/*
    connect(&this->chronoTimer(), &QgScopeChronoTimer::periodExpired, this,
            [this]()
            {
                //p_.s.writeDatagram((char*)p_.raw, sizeof p_.raw, QHostAddress("192.168.2.255"), rt_port);
                p_.bcFrameGenerator();
            }
        );

    connect(&p_.s, &QUdpSocket::readyRead, this,
            [this]()
            {
                //chronoTimer().start(10000);
                //p_.s.writeDatagram((char*)p_.raw, sizeof p_.raw, QHostAddress("192.168.2.255"), rt_port);
                p_.bcReceive();
            }
        );
*/
    connect(this, &AvbDriverUDP::_sigStart, this, &AvbDriverUDP::bcStart, Qt::QueuedConnection);
    connect(this, &AvbDriverUDP::_sigStop, this, &AvbDriverUDP::bcStop, Qt::QueuedConnection);

    connect(this, &AvbDriverUDP::_sigInit, this, &AvbDriverUDP::onInit, Qt::QueuedConnection);

    p_.thread.start(QThread::HighestPriority);

    Q_EMIT _sigInit();


    {
        QSettings s("./gmcs.ini", QSettings::IniFormat);
        s.beginGroup("Udp1553Server");
        bool active=s.value("active", false).toBool();
        s.endGroup();
        p_.server=0;
        p_.remoteSocket=0;
        if (active)
        {
            p_.server=new QLocalServer;
            p_.server->setMaxPendingConnections(1);
            p_.server->listen("Udp1553Server");
            connect(p_.server, &QLocalServer::newConnection, this, &AvbDriverUDP::serverNewConnection);
        }
    }
}

void AvbDriverUDP::serverNewConnection()
{
    p_.remoteSocket=p_.server->nextPendingConnection();
}

void AvbDriverUDP::onInit()
{

    p_.s.moveToThread(&p_.thread);

    if (p_.ha.isNull())
        p_.ha=QgNetworkInterface::networkInterface();
    p_.s.bind(p_.ha, bc_port);
    //p_.tgtHost=QgRexNetwork().networkBroadcast();

    connect(&this->chronoTimer(), &QgScopeChronoTimer::periodExpired, this,
            [this]()
            {
                //p_.s.writeDatagram((char*)p_.raw, sizeof p_.raw, QHostAddress("192.168.2.255"), rt_port);
                p_.bcFrameGenerator();
            }
        );

    connect(&p_.s, &QUdpSocket::readyRead, this,
            [this]()
            {
                //chronoTimer().start(10000);
                //p_.s.writeDatagram((char*)p_.raw, sizeof p_.raw, QHostAddress("192.168.2.255"), rt_port);
                p_.bcReceive();
            }
        );
}

AvbDriverUDP::~AvbDriverUDP()
{
}

bool AvbDriverUDP::initialize()
{
    return true;
}

void AvbDriverUDP::set_begin_of_major_frame_handler(avb_1553_major_frame_handler_t handler)
{
    dd.beginHandler=handler;
}

void AvbDriverUDP::set_minor_frame_handler(avb_1553_major_frame_handler_t handler)
{
    dd.minorHandler=handler;
}

void AvbDriverUDP::set_end_of_frame_handler(avb_1553_major_frame_handler_t handler)
{
    dd.majorHandler=handler;
}

const char* AvbDriverUDP::getDeviceName()
{
    return "Rex::AVB1553UDP";
}

bool AvbDriverUDP::setUpBcFrame(avb_1553_bc_frame_t& frame)
{
    dd.bc_frame=frame;

    int nmsg=frame.num_of_message;
    avb_1553_bc_message_t** table=frame.msg;
    if (!table)
        return false;

    memset(&dd.bcPreparedMsg, 0, sizeof dd.bcPreparedMsg);

    udp_1553_header_t* h=(udp_1553_header_t*)&dd.bcPreparedMsg;
    h->marker1553=udp_1553_header_t::k_marker_1553;
    //h->ttag=0;
    //h->frame_counter=0;
    //h->spare=0;

    udp_1553_msg_t* p=(udp_1553_msg_t*)&(h[1]);

    dd.bcPreparedSize=sizeof *h;

    bool skip_next=false;

    for(int i=0; i<nmsg; ++i)
    {
        avb_1553_bc_message_t* m=table[i];
        if (!m)
            break;
        if (m->msg==avb_frame_end_of_minor)
            continue;
        if (m->msg==avb_frame_end_of_major)
            continue;
        if (m->msg==avb_frame_skip_next_message)
        {
            skip_next=true;
            continue;
        }

        //qDebug()<<"Frame:"<<i<<m->msg->nickName;

        if (m->msg->target->adr!=20)
            continue;

        if (m->msg->type!=avb_t_auto)
            continue;

        int rxtx=m->msg->tr ? 1 : 0;
        unsigned int sa=m->msg->sa;
        if (sa>31)
            continue;

        ctrl_info_t* ctrl=&dd.ctrl_info[rxtx][sa];

        ctrl->conditional=false;
        ctrl->frq_coundown=0;
        ctrl->skip_words=4;

        if (ctrl->handler) //dd.bcHandlers[rxtx][sa])
        {
            ++ctrl->frq;
            ++ctrl->conditional=skip_next;
            continue;
        }
        skip_next=false;

        avb_1553_cmd_word_t cw;
        int wc=m->msg->wc;

        cw.raw=0;
        cw.str.rt=m->msg->target->adr;
        cw.str.sa=sa;
        cw.str.tr=rxtx;
        cw.str.wc=wc;
        ctrl->handler=m; //dd.bcHandlers[rxtx][sa]=m;

        //qDebug()<<"+++:"<<i<<m->msg->nickName<<sa<<rxtx;

        ctrl->ctrl=(udp_1553_msg_t*)&p;
        p->marker=0;
        p->cw=cw.raw;
        p->sw=0;
        p->errcode=0;

        if ((sa==0) || (sa==31))
                wc=1;

        uint16_t* wp=(uint16_t*)&p[1];

        m->msg->buffer=(avb_1553_data_buffer_t*)dd.buffersRxTx[rxtx][sa]; //(avb_1553_data_buffer_t*)wp;

        p=(udp_1553_msg_t*)&wp[wc];

        dd.bcPreparedSize+=wc*2 + sizeof *p;

        ctrl->skip_words+=wc;

    }

    return true;
}

#define BC_PERIOD   10000 /*1000000*/
void AvbDriverUDP::bcStart()
{
    dd.run_sts=IAvbDriver::sts_bc_run;
    qDebug()<<"AvbUDP:"<<1000000;

    this->chronoTimer().start(BC_PERIOD);
}

void AvbDriverUDP::bcStop()
{
    dd.run_sts=IAvbDriver::sts_halt;
    this->chronoTimer().stop();
    p_.bc_connected=false;
}

void AvbDriverUDP::monStart()
{
    dd.run_sts=IAvbDriver::sts_mon_run;
    this->chronoTimer().start(BC_PERIOD);
}

void AvbDriverUDP::monHalt()
{
    dd.run_sts=IAvbDriver::sts_halt;
    this->chronoTimer().stop();
}

void AvbDriverUDP::set_isr(avb_1553_isr_t)
{
    return;
}

bool AvbDriverUDP::go(int times)
{
    //dd.run_sts=IAvbDriver::sts_bc_run;
    //this->chronoTimer().start(1000000);
    Q_EMIT _sigStart();
    return true;
}

bool AvbDriverUDP::stop()
{
    //dd.run_sts=IAvbDriver::sts_bc_run;
    //this->chronoTimer().stop();
    Q_EMIT _sigStop();
    return true;
}

bool AvbDriverUDP::shutdown()
{
    return stop();
}

bool AvbDriverUDP::go_mon()
{
    return true;
}

bool AvbDriverUDP::halt_mon()
{
    return true;
}

IAvbDriver::run_status_t AvbDriverUDP::getRunState()
{
    return dd.run_sts; //sts_halt;
}

void AvbDriverUDP::niceInterrupt(bool enable)
{
    return;
}

void AvbDriverUDP::enableMonitorIsr(bool /*enable*/)
{
    return;
}
void AvbDriverUDP::set_mon_isr(avb_1553_monitor_isr_t isr)
{
    dd.mon_isr=isr;
    return;
}

bool AvbDriverUDP::getMonitorRawBuffer(avb_1553_monitor_info_t* const buffer)
{
    static avb_1553_mon_decoded_t msg[mon_max_msg];
    unsigned int n=dd.mon.info.total_message;
    if (n<1)
        return false;
    unsigned int size=n*(sizeof(avb_1553_mon_decoded_t));
    memcpy(msg, dd.mon.msg, size);

    for(unsigned int i=0; i<n; ++i)
    {
        msg[i].next=&msg[i+1];
    }
    msg[n-1].next=0;
    *buffer=dd.mon.info;
    buffer->buffer=(avb_1553_word_t*)msg;
    buffer->size=size;
    dd.mon.info.total_message=0;
    dd.mon.info.processed_message=0;

    return true;
}

int AvbDriverUDP::getLastDriverError()
{
    return 0;
}
const char* AvbDriverUDP::getDriverErrrorMessage(int error_code)
{
    return "?";
}

bool AvbDriverUDP::readDataBuffer(avb_1553_message_t* const m, void* const dst, unsigned int wc)
{
    if (m && m->buffer)
    {
        if (wc==0)
            wc=m->wc;
        if (wc>32)
            return false;

        memcpy(dst, dd.buffersRxTx[m->tr][m->sa], wc*2);
        //memcpy(dst, m->buffer, wc*2);
        return true;
    }
    return false;
}

bool AvbDriverUDP::writeDataBuffer(const avb_1553_message_t* const m, void* const src, unsigned int wc)
{
    if (m && m->buffer)
    {
        if (wc==0)
            wc=m->wc;
        if (wc>32)
            return false;
        //memcpy(m->buffer, src, wc*2);
        memcpy(dd.buffersRxTx[m->tr][m->sa], src, wc*2);

        return true;
    }
    return false;
}

void AvbDriverUDP::writeSyncWord(avb_1553_word_t w)
{
    dd.buffersRxTx[0][0][0]=w;
    return;
}

bool AvbDriverUDP::insertMessage(const avb_1553_bc_message_t* const m)
{
    return false;
}

bool AvbDriverUDP::enableSkipMessage(bool enable)
{
    dd.skip_next_enabled=enable;
    return true;
}

//bool adjustMinorFrameTimer();
avb_1553_intr_status_t AvbDriverUDP::getIntrStatus()
{    
    return dd.ists;
}

bool AvbDriverUDP::mon_decode_msg(avb_1553_mon_decoded_t* const decoded, void* const buffer)
{
    if (buffer)
    {
        memcpy(decoded, buffer, sizeof *decoded);
        return true;
    }
    return false;
}

avb_microseconds_t AvbDriverUDP::getTimetag()
{
    return chronoTimer().timeNow()-tt_base;
}

void AvbDriverUDP::simulateBcTick()
{
}


IAvbDriver* RexAvdDriveCreate(const QHostAddress *ha)
{
    static AvbDriverUDP d(ha);
    return &d;
}

