/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: CE-MUX-Driver
 *****************************************************************************
 * Author : Siemens AG Berlin COM WM RD SW
 *****************************************************************************
 * $Workfile: O:/mwohler_z_ms-d/z_ms-d/src/working/Classic/MuxDrv/MuxProt/ddmpiov2.c $
 * $Revision: /main/ms-d/13 $
 * $Date: 2014-03-14 11:54:05 $
 * $Author: mwohler $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 4.2 or 5.0
 *****************************************************************************
 *
 * $Log: O:/mwohler_z_ms-d/z_ms-d/src/working/Classic/MuxDrv/MuxProt/ddmpiov2.c$ 
 * 
 * /main/ms-d/13   2014-03-14 11:54:05   mwohler 
 * Use latest version of mux protocol implementation based on development for Miami client driver 
 * 
 * /main/ms-d/12   2009-02-18 11:58:48   ctna0256 
 * Set copyright text 
 * 
 * /main/ms-d/11   2008-11-21 10:44:33   ctna0450 
 * Switch to 32 bit buffer handling to allow any mux frame size.
 * Increase max. mux frame size from 244 bytes to 16 kilo bytes.
 *
 * /main/ms-d/10   2008-08-20 11:38:14   ctna0450
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/9   2006-08-24 12:32:06   kr36712
 * correction: the protocol version negotiation does not function after restart of the mux protocol
 *
 * /main/ms-d/8   2006-07-27 17:14:52   kr36712
 * HDLC integration
 *
 * /main/ms-d/7   2005-11-08 17:12:44   kr36712
 * the protocol is suitable for several instances
 *
 * /main/ms-d/6   2005-11-01 10:53:43   wm36264
 * Removed some obsolete compiler flags
 *
 * /main/ms-d/5   2005-10-28 16:20:46   kr36712
 *
 * /main/ms-d/4   2005-10-20 13:54:25   WM36264
 * Added proper copyright header
 *
 * /main/ms-d/3   2005-10-19 10:48:16   WM36264
 * Removed obsolete header files
 *
 * /main/ms-d/2   2005-10-10 15:36:07   wm36264
 * Reworked macros for debug output
 *
 * /main/ms-d/1   2005-10-07 16:29:19   wm36264
 * First version of Windows CE Muxer
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Cinterion Wireless Modules GmbH
// Copyright (C) 2005-2008 Siemens AG
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#include "global.h"
#include "mux_callback.h"
#include "ddmpglob.h"
#include "ddmpdlch.h"
#include "ddmpiofunc.h"


//***** Prototypes ***********************************************************
void MP_RxFraming(MUX_INSTANCE_t *pMux, UINT8 *pStart, UINT8 *pStop);
void MP_RxFramingHdlc(MUX_INSTANCE_t *pMux, UINT8 *pStart, UINT8 *pStop);


//***** EXIT CODES ************************************************************
#define MP_IO_WRONG_INSTANCE        0


/*****************************************************************************/
/* ---------------------------------------------------------------------------
 * scope:
 * input:   Pointer and Len  DEV -> MP
 * returns: data written
 * ---------------------------------------------------------------------------
 * descr:   read framed data from connected (serial) driver
 *
 * ---------------------------------------------------------------------------
 */
UINT32 MP_uiDevDataReceive
(
    MUX_INSTANCE_t  *pMux,
    UINT8           *Data,
    UINT32           len
)
{
    UINT8 count;

    if (pMux->MP_uiUsedProtVersion != MP_REVISION_04)
    {
        MP_RxFraming(pMux, Data, Data + len);

        for (count = DLCI1; count < pMux->dwMaxNumberOfDLCI; count++)
        {
          if (pMux->pDLCIArray[count].MP_RxRingBuf.Count)
          {
              MP_vSetRXLoop(pMux, (UINT8)(count | MP_RXLOOP_HIGHPRIO));
          }
        }
    }
    else
    {
        MP_RxFramingHdlc(pMux, Data, Data + len);
    }

    return len;
}

/*****************************************************************************/
/* ---------------------------------------------------------------------------
 * scope:
 * input:
 * returns:
 * ---------------------------------------------------------------------------
 * descr:   WriteDataCallback                            DEV -> MP
 *          Wakes up Mux to write framed data to device
 * ---------------------------------------------------------------------------
 */
void MP_vDevDataSendCallback
(
  MUX_INSTANCE_t  *pMux,
  UINT32           len
)
{
    MP_vSetTXLoop(pMux); // TX-Loop not loger needs any instance, so we send DLCI0 as a dummy
}



UINT32 MP_uiAppDataReceive
(
    MUX_INSTANCE_t  *pMux,
    UINT8           *Data,
    UINT32           len,
    UINT8            ucDlci
)
{
    UINT8   state;

    if ((ucDlci == DLCI0) || (ucDlci >= pMux->dwMaxNumberOfDLCI))
    {
        MUX_EXIT((TEXT("MuxDrv: Mux-Exit: %d"), MP_IO_WRONG_INSTANCE));
    }
    state = MP_eGetState(pMux, ucDlci);

    // check if channel is connected
    if ((DLC_CONNECTED != state) && (DLC_CONNECTEDWAIT4RESPONSE != state))
    {
        MUXDBG(ZONE_MUX_PROT2, (TEXT("MuxDrv: Channel not connected dlci=%d len=%d state=%d"), ucDlci, len, state));
        /* discard data */
        return len;
    }

    return MP_uiToTxBufTransparent(pMux, Data, len, ucDlci);
}

void MP_vAppDataSendCallback
(
    MUX_INSTANCE_t  *pMux,
    UINT8            ucDlci
)
{
    MP_vSetRXLoop(pMux, ucDlci  | MP_RXLOOP_HIGHPRIO);
}


void MP_vAppSetV24Status
(
    MUX_INSTANCE_t  *pMux,
    V24STATUS        status,
    UINT8            ucDlci
)
{
    BOOL bStatusChanged = FALSE;
    V24STATUS MyStatus = pMux->pDLCIArray[ucDlci].sMP_DLCI.sV24Status;

    if (pMux->ucInitiator) // customer application is always master
    {
        if (MyStatus.DTR != status.DTR) {
            MyStatus.DTR = status.DTR;
            bStatusChanged = TRUE;
        }

        if (MyStatus.RTS != status.RTS)   {
            MyStatus.RTS = status.RTS;
            bStatusChanged = TRUE;
        }
    }
    else // module is always slave
    {
        if (MyStatus.CTS != status.CTS) {
            MyStatus.CTS = status.CTS;
            bStatusChanged = TRUE;
        }

        if (MyStatus.RI != status.RI)   {
            MyStatus.RI = status.RI;
            bStatusChanged = TRUE;
        }

        if (MyStatus.DSR != status.DSR) {
            MyStatus.DSR = status.DSR;
            bStatusChanged = TRUE;
        }

        if (MyStatus.DCD != status.DCD) {
            MyStatus.DCD = status.DCD;
            bStatusChanged = TRUE;
        }
    }

    // transmit the status changes using a MSC frame over the channel
    if (bStatusChanged)
    {
        // the new bits have been already written in this function
        pMux->pDLCIArray[ucDlci].sMP_DLCI.sV24Status = MyStatus;

        if (MP_bDlciConnected(pMux, ucDlci))
        {
            // Nur, wenn der Kanal logisch verbunden ist
            MP_WriteRequest_V24Ind(pMux, ucDlci);
        }
    }
    if (!pMux->ucInitiator) // only on module side
    {
        BOOL PhysRI = FALSE, PhysDCD = FALSE;
        // from compatibility reasons the physical lines are a sum signal from
        // all logical channels for DCD and RING. If any channel has a logical
        // RING, the hardware ports RING is set, too. The same comes with DCD
        if (Mux_DevGetV24Lines_cb(pMux, &PhysRI, &PhysDCD)) {
            UINT8  i;
            BOOL   WiredRI = FALSE, WiredDCD = FALSE;

            bStatusChanged = FALSE;

            for (i = 1; i < pMux->dwMaxNumberOfDLCI; i++) {
                if (pMux->pDLCIArray[i].sMP_DLCI.sV24Status.RI)  WiredRI  = TRUE;
                if (pMux->pDLCIArray[i].sMP_DLCI.sV24Status.DCD) WiredDCD = TRUE;
            }

            if (PhysRI != WiredRI) {
                bStatusChanged = TRUE;
                PhysRI = WiredRI;
            }

            if (PhysDCD != WiredDCD) {
                bStatusChanged = TRUE;
                PhysDCD = WiredDCD;
            }

            if (bStatusChanged)
            {
                Mux_DevSetV24Lines_cb(pMux, PhysRI, PhysDCD);
            }
        }
    }
}


/*****************************************************************************/
/* ---------------------------------------------------------------------------
 * scope:
 * input:   Len
 * returns:
 * ---------------------------------------------------------------------------
 * descr:   callback to connected application to write more unframed
 *          data into the mux APPi -> MP
 * ---------------------------------------------------------------------------
 */
void MP_vAppCallback
(
    MUX_INSTANCE_t  *pMux,
    UINT8           ucDlci,
    UINT32          len
)
{
    if ((ucDlci == DLCI0) || (ucDlci >= pMux->dwMaxNumberOfDLCI))
    {
        MUX_EXIT((TEXT("MuxDrv: Mux-Exit: %d"), MP_IO_WRONG_INSTANCE));
    }
    // wake up application via callback if in stopped state
    if (pMux->MP_uiUsedProtVersion < MP_REVISION_04)
    {
        if (pMux->pDLCIArray[ucDlci].MP_TxRingBuf.Count < (pMux->pDLCIArray[ucDlci].MP_TxRingBuf.BufSize / 8))
        {
            MP_vAppReceiveDataCallback(pMux, 0, ucDlci);
        }
    }
    else
    {
        if (pMux->pDLCIArray[ucDlci].MP_TxRingBuf.Count < (pMux->pDLCIArray[ucDlci].MP_TxRingBuf.BufSize / 2))
        {
            MP_vAppReceiveDataCallback(pMux, 0, ucDlci);
        }
    }
}


/*****************************************************************************/
/* ---------------------------------------------------------------------------
 * scope:
 * input:
 * returns:
 * ---------------------------------------------------------------------------
 * descr:   Read physical V24Values from Device, fill into MUX_DEVICE
 *          send all V24signals per selected version
 * ---------------------------------------------------------------------------
 */
void MP_vSendMSCInitialValues
(
    MUX_INSTANCE_t  *pMux,
    UINT8            ucDlci
)
{
    if (ucDlci == 1)
    {
        BOOL bRing, bDCD;
        if (Mux_DevGetV24Lines_cb(pMux, &bRing, &bDCD)) {
            // fill V24structs with values from original device
            pMux->pDLCIArray[ucDlci].sMP_DLCI.sV24Status.RI  = bRing;
            pMux->pDLCIArray[ucDlci].sMP_DLCI.sV24Status.DCD = bDCD;
        }
    }
    MP_vMSC_SendMSC(pMux, ucDlci, 0);
}


void MP_Init
(
    MUX_INSTANCE_t  *pMux
)
{
    MP_PRIMITIVE sPrimitive;

    // standard initialization functions for the mux parts
    MP_vInitScanner(pMux);
    MP_vMemInit(pMux);
    MP_vStatemachineInit(pMux);

    // system depending initialization
    MP_vInitAdaptation(pMux);

    // sent first message to indicate startup to mux state machine
    sPrimitive.Event    = MP_IndStartUp;
    sPrimitive.ucDLCI   = DLCI0;
    MP_PostUserMessage(pMux, &sPrimitive);
}


/*****************************************************************************/
/* ---------------------------------------------------------------------------
 * scope:
 * input:   EVENT, CHANNEL ID
 * returns: void
 * ---------------------------------------------------------------------------
 * descr:   sends a specified message with only one param, the channel, to the
 *          statemachine
 * ---------------------------------------------------------------------------
 */
void MP_PostSimpleUserMessage
(
    MUX_INSTANCE_t  *pMux,
    MP_EVENT_TYPE    evnt,
    UINT8            dlci
)
{
    MP_PRIMITIVE prim;
    prim.Event    = evnt;
    prim.ucDLCI   = dlci;
    prim.ulParam  = 0;
    prim.pucPtr   = NULL;
    MP_PostUserMessage(pMux, &prim);
}

/*****************************************************************************/

void MP_StartShutdownProc
(
    MUX_INSTANCE_t  *pMux
)
{
    MUXDBG(ZONE_MUX_PROT1, (TEXT("MuxDrv: MP_StartShutdownProc()")));
    MP_PostSimpleUserMessage(pMux, MP_ReqCloseDown, DLCI0);
}


/********************************************************************************/
/**
    upper layer calls here, to request a given low power state
    -> Mux sends PSC command

\return  none
*/
void MP_SleepReqEx
(
    MUX_INSTANCE_t  *pMux,
    MP_ePSCMode      newMode
)
{
    MP_PRIMITIVE   sPrimitive;

    sPrimitive.Event  =  MP_ReqPSC;
    sPrimitive.ucDLCI =  DLCI0;

    PRIM_WRITE_PSC_MODE(&sPrimitive, newMode);

    MP_PostUserMessage(pMux, &sPrimitive);
}

/* EOF */
