// $Id: melbee.cpp,v 1.3 2003/03/23 06:20:50 fukasawa Exp $

// ============================================================================
//
// = LIBRARY
//     tclmelsec
//
// = FILENAME
//     melbee.cpp
//
// = AUTHOR(S)
//     Fukasawa Mitsuo
//
// = COPYRIGHT
//     Copyright (c) 2001-2002 by BEE Co.,Ltd.  All rights reserved.
//
//     This file is part of the tclgxml that can be used free.
//     The tclgxml and this file are covered by the GNU Lesser General Public
//     License, which should be included with libxml++ as the file COPYING.
//
// ============================================================================

#ifdef _MSC_VER
#pragma warning(disable: 4786)  // too long identifier
#endif

#include "PLCMemory.h"
#include "MELDeviceManager.h"
#ifdef _MSC_VER
#include <windows.h>
#endif
#include "tclbee.h"


/*---------------------------------------------------------------------------*/
/*                                                                           */
/*  Parse device type                                                        */
/*                                                                           */
/*---------------------------------------------------------------------------*/
int parseMemoryAddr(Tcl_Interp * interp, char * devAddr,
                    PLCDevice ** retmem,  unsigned long * top)
{
    char devName[8];

    MELDeviceManager * melmngr = MELDeviceManager::instance();
    if (melmngr == NULL)
    {
        return TCL_ERROR;
    }
    u_int pos = strcspn(devAddr, "0123456789");
    if (pos >= strlen(devAddr) || pos < 0 || pos >= sizeof(devName))
    {
        Tcl_AppendResult(interp, "illegal address format \"", devAddr, "\" ",
                         NULL);
        return TCL_ERROR;
    }
    memmove(devName, devAddr, pos);
    if (devName[pos - 1] == ':')
        devName[pos - 1] = '\0';
    else
        devName[pos] = '\0';

    PLCDevice * mem = melmngr->get(devName);
    if (mem == NULL)
    {
        Tcl_AppendResult(interp, "illegal device type \"", devName, "\" ",
                         NULL);
        return TCL_ERROR;
    }

    *top = strtoul(devAddr + pos, NULL, 0);
    if (*top >= mem->size())
    {
        Tcl_AppendResult(interp, "illegal address \"", devAddr + pos, "\" ",
                         NULL);
        return TCL_ERROR;
    }
    *retmem = mem;
    return TCL_OK;
}


/*---------------------------------------------------------------------------*/
/*                                                                           */
/*  Parse device size                                                        */
/*                                                                           */
/*---------------------------------------------------------------------------*/
int parseSize(Tcl_Interp * interp, PLCDevice * mem, char * sizeStr,
                     size_t * size)
{
    if (EQUALSTR(sizeStr, "end"))
        *size = ACTION_END;
    else
    {
        *size = strtoul(sizeStr, NULL, 0);
        if (*size <= 0)
        {
            Tcl_AppendResult(interp, " invalid short size \"", sizeStr,
                             "\"", NULL);
            return TCL_ERROR;
        }
    }
    return TCL_OK;
}


/*---------------------------------------------------------------------------*/
/*                                                                           */
/*  Parse device data                                                        */
/*                                                                           */
/*  * Caller must free buffer which is returnd                               */
/*                                                                           */
/*---------------------------------------------------------------------------*/
int parseWordData(Tcl_Interp * interp, char * datastr,
                  unsigned short ** bufpp, size_t * size)
{
    int  result;
    int  count, i, j;
    const char **lists;
    unsigned short * databuf;

    result = Tcl_SplitList(interp, datastr, &count, &lists);
    if (result != TCL_OK)
    {
        return result;
    }

    if ((databuf = (unsigned short *)malloc(count * sizeof(short))) == NULL)
    {
        Tcl_AppendResult(interp, " empty memory ", (char *)NULL);
        return TCL_ERROR;
    }

    for (i = j = 0; i < count; i++)
    {
        databuf[j] = (unsigned short)strtol(lists[i], NULL, 0);
        j++;
    }
    Tcl_Free((char *)lists);
    *bufpp = databuf;
    *size = j;

    return TCL_OK;
}

/*---------------------------------------------------------------------------*/
int parseBitData(Tcl_Interp * interp, char * datastr,
                        unsigned short ** bufpp, size_t * size)
{
    int  result;
    int  count, i, j;
    int  sc;
    const char **lists;
    unsigned short * databuf;

    result = Tcl_SplitList(interp, datastr, &count, &lists);
    if (result != TCL_OK)
    {
        return result;
    }
    sc = (count + BITS_OF_SHORT) / BITS_OF_SHORT;
    if ((databuf = (unsigned short *)malloc((sc + 1) * sizeof(short))) == NULL)
    {
        Tcl_AppendResult(interp, " empty memory ", (char *)NULL);
        return TCL_ERROR;
    }

    unsigned short bits = 0;
    for (i = j = 0; i < count; i++)
    {
        if ((i != 0) && (i % BITS_OF_SHORT == 0))
        {
            databuf[j++] = bits;
            bits = 0;
        }
        size_t bitnum = i & MASK_OF_SHORT;
        int bit = strtol(lists[i], NULL, 10);
        if (bit != 0)
        {
            bits |= PLCBitMemory::BitPattern[bitnum];
        }
    }
    databuf[j] = bits;
    Tcl_Free((char *)lists);
    *bufpp = databuf;
    *size = count;
    return TCL_OK;
}

/*---------------------------------------------------------------------------*/
int parseData(Tcl_Interp * interp, char * datastr,
              unsigned short ** bufpp, size_t * size)
{
    int  result;
    int  count, i, j;
    const char **lists;
    unsigned short * databuf;

    result = Tcl_SplitList(interp, datastr, &count, &lists);
    if (result != TCL_OK)
    {
        return result;
    }

    if ((databuf = (unsigned short *)malloc(count * sizeof(short))) == NULL)
    {
        Tcl_AppendResult(interp, " empty memory ", (char *)NULL);
        return TCL_ERROR;
    }

    for (i = j = 0; i < count; i++)
    {
        if (i == 0 || ((i % 9) == 0))   /* Ignore pointer */
            continue;
        databuf[j] = (unsigned short)strtol(lists[i], NULL, 16);
        j++;
    }
    Tcl_Free((char *)lists);
    *bufpp = databuf;
    *size = j;

    return TCL_OK;
}


