// $Id: JGWordSetSensor.cpp,v 1.6 2003/02/09 16:15:13 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGWordSetSensor.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 "sac/JGWordSetSensor.h"
#include "JGVariable.h"
#include "JGTriggerInfo.h"

//-----------------------------------------------------------------------------
// Constructor/Destractor
//-----------------------------------------------------------------------------
JGWordSetSensor::JGWordSetSensor() : JGIODevice(), m_first(true)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGWordSetSensor::JGWordSetSensor");
    m_words = m_dimension;
    m_saved = (u_short *)calloc(m_words, sizeof(short));
    m_readbuf = (u_short *)calloc(m_words, sizeof(short));
    for (int i = 0; i < m_dimension; i++)
    {   // Clear elements
        m_vars.push_back(NULL);
    }
}

//-----------------------------------------------------------------------------
JGWordSetSensor::JGWordSetSensor(const JGIODevice& rhs) : JGIODevice(rhs)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGWordSetSensor::JGWordSetSensor");
    m_words = m_dimension;
    m_first = true;
    m_saved = (u_short *)calloc(m_words, sizeof(short));
    m_readbuf = (u_short *)calloc(m_words, sizeof(short));
    for (int i = 0; i < m_dimension; i++)
    {   // Clear elements
        m_vars.push_back(NULL);
    }
}

//-----------------------------------------------------------------------------
JGWordSetSensor::~JGWordSetSensor()
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGWordSetSensor::~JGWordSetSensor");
    if (m_saved != NULL)
    {
        free(m_saved);
    }
    if (m_readbuf != NULL)
    {
        free(m_readbuf);
    }
}

//-----------------------------------------------------------------------------
// Copy
//-----------------------------------------------------------------------------
JGWordSetSensor& JGWordSetSensor::operator=(const JGWordSetSensor& rhs)
{
    TRACE_FUNCTION(TRL_CONSTRUCT, "JGWordSetSensor::operator=");
    if (this == &rhs)
        return *this;

    (JGIODevice&)(*this) = rhs;

    if (m_saved != NULL)
    {
        free(m_saved);
    }
    if (m_readbuf != NULL)
    {
        free(m_readbuf);
    }
    m_words = rhs.m_words;
    int byte_size = m_words * sizeof(u_short);
    m_first = rhs.m_first;
    m_saved = (u_short *)malloc(byte_size);
    memmove(m_saved, rhs.m_saved, byte_size);
    m_readbuf = (u_short *)malloc(byte_size);
    memmove(m_readbuf, rhs.m_readbuf, byte_size);
    m_vars = rhs.m_vars;
    return *this;
}

//-----------------------------------------------------------------------------
// Append variable info.
//-----------------------------------------------------------------------------
int JGWordSetSensor::add(JGVariable * var)
{
    TRACE_FUNCTION(TRL_LOW, "JGWordSetSensor::add");

    // Read memory block
    if (var->offset() >= m_dimension)
    {
        TRACE_ERROR((_TX("Illegal offset (0x%x)\n"), var->offset()));
        return BEE_ERROR;
    }

    if (m_vars[var->offset()] != NULL)
    {
        TRACE_ERROR((_TX("Duplicate variable data (0x%x)\n"), var->offset()));
        return BEE_ERROR;
    }

    m_vars[var->offset()] = var;
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Initial current value.
//-----------------------------------------------------------------------------
int JGWordSetSensor::init()
{
    TRACE_FUNCTION(TRL_LOW, "JGWordSetSensor::init");
    if (! m_first)
    {
        return BEE_SUCCESS;
    }

    // Read memory block
    int result = m_plc.memory()->read(m_plc.addr(), m_dimension, m_saved);
    if (result < 0)
    {
        TRACE_ERROR((_TX("PLC read error\n")));
        return BEE_ERROR;
    }

    for (int i = 0; i < m_dimension; i++)
    {
        if (m_vars[i] == NULL)
        {
            continue;
        }
        JGvalue val = m_saved[i];
        m_vars[i]->curval(val);
    }

    m_first = false;
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Check to update bit registers, and notify event.
//-----------------------------------------------------------------------------
int JGWordSetSensor::sense()
{
    TRACE_FUNCTION(TRL_LOW, "JGWordSetSensor::sense");

    vector<JGVariable *> trg_vars;
    int byte_size = m_words * sizeof(short);

    // Read memory block
    int result = m_plc.memory()->read(m_plc.addr(), m_dimension, m_readbuf);
    if (result < 0)
    {
        TRACE_ERROR((_TX("PLC read error\n")));
        return BEE_ERROR;
    }

    // Compare latest and current
    for (int i = 0; i < m_dimension; i++)
    {
        if (m_vars[i] == NULL)
        {   // Ignore reserve bit
            continue;
        }
        u_short saved = m_saved[i];
        u_short cur   = m_readbuf[i];
        u_short diff = saved ^ cur;
        if (diff != 0)
        {
            JGvalue val = cur;
            m_vars[i]->curval(val);
            trg_vars.push_back(m_vars[i]);    // Entry trigger info
        }
    }

    // Update latest data 
    memmove(m_saved, m_readbuf, byte_size);

    // Issue trigger
    if (trg_vars.size() > 0 && m_subject != NULL)
    {
        m_subject->changed(trg_vars);
    }

    return trg_vars.size();
}

