/* ======================================================================== *\
!
! *
! * This file is part of Stesy, the MAGIC Steering System
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Thomas Bretz <mailto:tbretz@uni-sw.gwdg.de>, 2001
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

///////////////////////////////////////////////////////////////////////
//
// NodeDrv
//
// Base class for a class describing the interface for the CAN nodes.
//
// to be overloaded:
//  virtual void InitDevice(Network *net)
//  virtual void StopDevice()
//  virtual void HandleSDO(WORD_t idx, BYTE_t subidx, LWORD_t val, timeval_t *tv)
//  virtual void HandleSDOOK(WORD_t idx, BYTE_t subidx)
//  virtual void HandleSDOError(LWORD_t data)
//  virtual void HandlePDO1(BYTE_t *data, timeval_t *tv)
//  virtual void HandlePDO2(BYTE_t *data, timeval_t *tv)
//  virtual void HandlePDO3(BYTE_t *data, timeval_t *tv)
//  virtual void HandlePDO4(BYTE_t *data, timeval_t *tv)
//
///////////////////////////////////////////////////////////////////////
#include "nodedrv.h"

#include <iomanip.h>
#include <iostream.h>

#include "network.h"
#include "MLogManip.h"

ClassImp(NodeDrv);

// --------------------------------------------------------------------------
//
// Constructor for one node. Sets the Node Id (<32) the logging stream
// and the node name. The name is a name for debug output.
//
NodeDrv::NodeDrv(BYTE_t nodeid, const char *name, MLog &out) : Log(out), fNetwork(NULL), fId(32), fError(0)
{
    if (nodeid>0x1f)
    {
        cout << "SetNode - Error: Only node Numbers < 32 are allowed"<< endl;
        return;
    }

    fId = nodeid;

    if (name)
        fName = name;
    else
    {
        fName = "Node#";
        fName += (int)nodeid;
    }

    lout << "- Node #" << (int)nodeid << " (" << name << ") initialized." << endl;
}

// --------------------------------------------------------------------------
//
// Empty destructor
//
NodeDrv::~NodeDrv()
{
}

// --------------------------------------------------------------------------
//
// Init device, sets the pointer to the whole network and enables
// the Can messages to be passed through the interface:
//   PDO1 tx
//   PDO2 tx
//   PDO3 tx
//   PDO4 tx
//   SDO rx
//   SDO tx
//
void NodeDrv::InitDevice(Network *net)
{
    fNetwork = net;

    EnableCanMsg(kPDO1_TX);
    EnableCanMsg(kPDO2_TX);
    EnableCanMsg(kPDO3_TX);
    EnableCanMsg(kPDO4_TX);
    EnableCanMsg(kSDO_RX);
    EnableCanMsg(kSDO_TX);
}

// --------------------------------------------------------------------------
//
// Print an "SDO idx/subidx set." from this device message.
// This output is never redirected to the GUI
//
void NodeDrv::HandleSDOOK(WORD_t idx, BYTE_t subidx)
{
    const Bool_t gui = lout.IsOutputDeviceEnabled(MLog::eGui);

    if (gui)
        lout << ddev(MLog::eGui);

    lout << hex << setfill('0');
    lout << "Sdo=" << idx  << "/" << (int)subidx << " set.";
    lout << endl;

    if (gui)
        lout << edev(MLog::eGui);
}

// --------------------------------------------------------------------------
//
// Print an error message with the corresponding data from this device.
//
void NodeDrv::HandleSDOError(LWORD_t data)
{
    lout << "Nodedrv: SDO Error: Entry not found in dictionary (data=0x";
    lout << hex << setfill('0') << setw(4) << data << ")";
    lout << endl;
}

// --------------------------------------------------------------------------
//
// Prints the received SDo from this device
//
void NodeDrv::HandleSDO(WORD_t idx, BYTE_t subidx, LWORD_t val, timeval_t *tv)
{
    cout << "SdoRx: Idx=0x"<< hex << idx << "/" << (int)subidx;
    cout << ", val=0x" << val << endl;
}

// --------------------------------------------------------------------------
//
// Sends the given PDO1 through the network to this device
// A PDO is carrying up to eight bytes of information.
//
void NodeDrv::SendPDO1(BYTE_t data[8])
{
    fNetwork->SendPDO1(fId, data);
}

// --------------------------------------------------------------------------
//
// Sends the given PDO2 through the network to this device
// A PDO is carrying up to eight bytes of information.
//
void NodeDrv::SendPDO2(BYTE_t data[8])
{
    fNetwork->SendPDO2(fId, data);
}

// --------------------------------------------------------------------------
//
// Sends the given PDO1 through the network to this device
// A PDO is carrying up to eight bytes of information.
//
void NodeDrv::SendPDO1(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)
{
    fNetwork->SendPDO1(fId, m0, m1, m2, m3, m4, m5, m6, m7);
}

// --------------------------------------------------------------------------
//
// Sends the given PDO2 through the network to this device
// A PDO is carrying up to eight bytes of information.
//
void NodeDrv::SendPDO2(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)
{
    fNetwork->SendPDO2(fId, m0, m1, m2, m3, m4, m5, m6, m7);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, BYTE_t subidx, BYTE_t val, bool store)
{
    fNetwork->SendSDO(fId, idx, subidx, val, store);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, BYTE_t subidx, WORD_t val, bool store)
{
    fNetwork->SendSDO(fId, idx, subidx, val, store);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, BYTE_t subidx, LWORD_t val, bool store)
{
    fNetwork->SendSDO(fId, idx, subidx, val, store);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, BYTE_t val)
{
    fNetwork->SendSDO(fId, idx, val, true);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, WORD_t val)
{
    fNetwork->SendSDO(fId, idx, val, true);
}

// --------------------------------------------------------------------------
//
// Sends the given SDO through the network to this device
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to address
//  a subindex of this dictionary entry to access
//  and a value to set for this dictionary entry
//
void NodeDrv::SendSDO(WORD_t idx, LWORD_t val)
{
    fNetwork->SendSDO(fId, idx, val, true);
}

// --------------------------------------------------------------------------
//
// Request a SDO for a given idx/subidx
// An SDO message contains
//  an address (this device)
//  an index of the dictionary entry to read
//  a subindex of this dictionary entry to access
//
void NodeDrv::RequestSDO(WORD_t idx, BYTE_t subidx)
{
    fNetwork->RequestSDO(fId, idx, subidx);
}

// --------------------------------------------------------------------------
//
// Send an NMT message (command) to this device
//
void NodeDrv::SendNMT(BYTE_t cmd)
{
    fNetwork->SendNMT(fId, cmd);
}

// --------------------------------------------------------------------------
//
// Enable passthrough for the given functioncode of this device
//
void NodeDrv::EnableCanMsg(BYTE_t fcode)
{
    fNetwork->EnableCanMsg(fId, fcode, TRUE);
}

// --------------------------------------------------------------------------
//
// Wait a given timeout until the SDO with the given idx/subidx from
// this device has been received.
// You can stop waiting by StopWaitingForSDO.
//
void NodeDrv::WaitForSdo(WORD_t idx, BYTE_t subidx, WORDS_t timeout)
{
    fNetwork->WaitForSdo(fId, idx, subidx, timeout);
}

/*
void NodeDrv::WaitForSdos()
{
    while (fNetwork->WaitingForSdo(fId))
        usleep(1);
}
*/

// --------------------------------------------------------------------------
//
// Waits until the next Pdo1 from this device has been received
//
void NodeDrv::WaitForNextPdo1()
{
    fNetwork->WaitForNextPdo1(fId);
}

// --------------------------------------------------------------------------
//
// Waits until the next Pdo2 from this device has been received
//
void NodeDrv::WaitForNextPdo2()
{
    fNetwork->WaitForNextPdo2(fId);
}

// --------------------------------------------------------------------------
//
// Waits until the next Pdo3 from this device has been received
//
void NodeDrv::WaitForNextPdo3()
{
    fNetwork->WaitForNextPdo3(fId);
}

// --------------------------------------------------------------------------
//
// Waits until the next Pdo4 from this device has been received
//
void NodeDrv::WaitForNextPdo4()
{
    fNetwork->WaitForNextPdo4(fId);
}

