// $Id: JGPLCDevice.cpp,v 1.4 2003/03/11 14:45:16 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGPLCDevice.cpp
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2001-2003 BEE Co.,Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#define BEE_BUILD_DLL

#include "JGPLCDevice.h"
#include "PLCDevice.h"

//-----------------------------------------------------------------------------
// Copy
//-----------------------------------------------------------------------------
void JGPLCDevice::copy(const JGPLCDevice& rhs)
{
    TRACE_FUNCTION(TRL_LOW, "JGPLCDevice::copy");
    this->JGNameInfo::copy(rhs);
    m_name = rhs.m_name;
    m_sysid = rhs.m_sysid;
    m_devtype = rhs.m_devtype;
    m_datatype = rhs.m_datatype;
    m_iotype = rhs.m_iotype;
    m_format = rhs.m_format;
    m_viewFormat = rhs.m_viewFormat;
    m_dimension = rhs.m_dimension;
    m_dataq = rhs.m_dataq;
    m_value = rhs.m_value;
    m_maxval = rhs.m_maxval;
    m_minval = rhs.m_minval;
    m_plc = rhs.m_plc;
    m_lastAccess = rhs.m_lastAccess;
}

//-----------------------------------------------------------------------------
// Get data from i/o device.
//-----------------------------------------------------------------------------
JGvalue& JGPLCDevice::get()
{
    TRACE_FUNCTION(TRL_LOW, "JGPLCDevice::get");

    unsigned short datum;
    PLCDevice * io = m_plc.memory();
    BEEAssert(io != NULL);
    if (m_format == ATOM_ASCII)
    {
        char buf[8];
        buf[2] = '\0';
        string data;
        unsigned long pos = m_plc.addr();
        for (int i = 0; i < m_dimension; i++)
        {
            datum = io->get(pos);
            pos++;
            buf[0] = (datum >> 8) & 0xFF;
            buf[1] = datum & 0xFF;
            data += buf;
        }
        m_value = data;
    }
    else if (m_format == ATOM_INT4 || m_format == ATOM_UINT4)
    {
        unsigned int v;
        datum = io->get(m_plc.addr());
        v = datum << 16;
        datum = io->get(m_plc.addr() + 1);
        v += datum;
        m_value = v;
    }
    else if (m_format == ATOM_BOOLEAN)
    {
        bool bit = (io->get(m_plc.addr()) != 0) ? true : false;
        m_value = bit;
    }
    else if (m_format == ATOM_UINT1)
    {
        unsigned char v;
        datum = io->get(m_plc.addr());
        v = (unsigned char)(datum & 0xFF);
        m_value = v;
    }
    else if (m_format == ATOM_INT1)
    {
        char v;
        datum = io->get(m_plc.addr());
        v = (char)(datum & 0xFF);
        m_value = v;
    }
    else
    {
        datum = io->get(m_plc.addr());
        if (io->isBit())
        {
            m_value = (datum) ? true : false;
        }
        else
        {   // ATOM_INT2 or ATOM_UINT2
            m_value = datum;
        }
    }

    // Convert to view format
    if (m_viewFormat != m_format)
    {
        if (m_viewFormat == ATOM_ASCII)
        {
            string data = m_value.toString();
            m_value = data;
        }
        else if (m_viewFormat == ATOM_UINT4)
        {
            unsigned int v = m_value.getUInt();
            m_value = v;
        }
        else if (m_viewFormat == ATOM_INT4)
        {
            int v = m_value.getInt();
            m_value = v;
        }
        else if (m_format == ATOM_BOOLEAN)
        {
            bool bit = (m_value.getInt() != 0) ? true : false;
            m_value = bit;
        }
        else if (m_viewFormat == ATOM_UINT1)
        {
            unsigned char v = (unsigned char)m_value.getUInt();
            m_value = v;
        }
        else if (m_viewFormat == ATOM_INT1)
        {
            char v = (char)m_value.getInt();
            m_value = v;
        }
        else
        {
            m_value = datum;
        }
    }

    m_lastAccess = ACE_OS::gettimeofday();

    return m_value;
}

//-----------------------------------------------------------------------------
// Put data to i/o device.
//-----------------------------------------------------------------------------
int JGPLCDevice::put(JGvalue& val, bool sync)
{
    TRACE_FUNCTION(TRL_LOW, "JGPLCDevice::put");

    int result;
    unsigned short datum;
    PLCDevice * io = m_plc.memory();
    BEEAssert(io != NULL);

    if (m_format == ATOM_ASCII)
    {
        string valStr;
        val.get(valStr);
        const char * bufptr = valStr.c_str();
        int length = valStr.size();
        unsigned long pos = m_plc.addr();
        for (int i = 0; i < m_dimension; i++)
        {
            if ((i * 2) < length)
            {
                datum =  *(bufptr + (i * 2)) << 8;
                if ((i * 2 + 1) < length)
                    datum |= *(bufptr + (i * 2 + 1));
            }
            else
            {
                datum =  0;
            }
            result = io->put(pos, datum);
            pos++;
        }
    }
    else if (m_format == ATOM_INT4 || m_format == ATOM_UINT4)
    {
        unsigned int v = val.getUInt();
        datum = v >> 16;
        io->put(m_plc.addr(), datum);
        datum = v & 0xFFFF;
        result = io->put(m_plc.addr() + 1, datum);
    }
    else if (m_format == ATOM_BOOLEAN)
    {
        unsigned int v = val.getUInt();
        datum = (unsigned short)(v & 0xFFFF);
        result = io->put(m_plc.addr(), datum);
    }
    else
    {
        unsigned int v = val.getUInt();
        datum = (unsigned short)(v & 0xFFFF);
        result = io->put(m_plc.addr(), datum);
    }

    //### if (result >= 0)
    {
        if (sync)
        {   // Default: register equal current value.
            m_value = val;
        }
        m_lastAccess = ACE_OS::gettimeofday();
    }

    return result;
}

//-----------------------------------------------------------------------------
// Read data from i/o device.
//-----------------------------------------------------------------------------
int JGPLCDevice::sense()
{
    TRACE_FUNCTION(TRL_LOW, "JGPLCDevice::sense");

    int result = BEE_SUCCESS;
    JGvalue last = m_value;    // Save the last value
    this->get();
    if (last != m_value)
    {   // changed

        // update value of variable

        // trigger to observer
    }

    return result;
}

