/*---------------------------------------------------------------------------*
  Project:  NitroSDK - WM - libraries
  File:     wm_mp.c

  Copyright 2003,2004 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: wm_mp.c,v $
  Revision 1.7  2004/11/29 04:55:35  seiki_masashi
  fix typo

  Revision 1.6  2004/11/29 04:40:57  seiki_masashi
  Error when sendData in SetMPDataToPort and sendBuf in StartMP are the same.

  Revision 1.5  2004/10/22 04:37:28  terui
  Changed functions that return int type as WMErrCode so that they return WMErrCode enumerator type.

  Revision 1.4  2004/10/05 09:25:45  seiki_masashi
  Added the check code for the argument WM_SetMPData*

  Revision 1.3  2004/10/03 07:49:37  ooe
  Merged with ipl_branch. Added support for ignoreFatalError flag.

  Revision 1.2  2004/09/13 04:10:20  seiki_masashi
 Added WM_SetMPFrequency

  Revision 1.1  2004/09/10 11:03:30  terui
  New upload reflecting the breakup of wm.c.

  $NoKeywords: $
 *---------------------------------------------------------------------------*/

#include    <nitro/wm.h>
#include    "wm_arm9_private.h"


/*---------------------------------------------------------------------------*
  Name:         WM_StartMP

  Description:  Starts MP communication. Parent/child shared function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.
                recvBuf     -   Receive data storage buffer.
                                ARM7 writes data directly so be careful of cache.
                recvBufSize -   Size of receive data storage buffer.
                                Must be larger than WM_GetReceiveBufferSize() return value.
                sendBuf     -   Send data storage buffer.
                                ARM7 writes data directly so be careful of cache.
                sendBufSize -   Size of the send data storage buffer.
                                Must be larger than the WM_GetSendBufferSize() return value.
                mpFreq      -   How many times to MP communicate in one frame?
                               0 for consecutive send mode. Meaningful only for parents.

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_StartMP( WMCallbackFunc callback , u16* recvBuf , u16 recvBufSize , u16* sendBuf , u16 sendBufSize , u16 mpFreq )
{
    return WM_StartMPEx( callback, recvBuf, recvBufSize, sendBuf, sendBufSize, mpFreq, 0, FALSE, FALSE, FALSE, FALSE );
}

/*---------------------------------------------------------------------------*
  Name:         WM_StartMPEx

  Description:  Starts MP communication. Detailed operation mode can be specified. Parent/child shared function.

  Arguments:    callback        -   The callback function called when asynchronous process ends.
                recvBuf         -   Receive data storage buffer.
                                    ARM7 writes data directly so be careful of cache.
                recvBufSize     -   Size of receive data storage buffer.
                                    Must be larger than WM_GetReceiveBufferSize() return value.
                sendBuf         -   Send data storage buffer.
                                    ARM7 writes data directly so be careful of cache.
                sendBufSize     -   Size of send data storage buffer.
                                    Must be larger than the WM_GetSendBufferSize() return value.
                mpFreq          -   How many times to MP communicate in one frame?
                                    0 for consecutive send mode. Has meaning only for parent.
                defaultRetryCount - The standard number of times to retry when send fails
                                    during communication of 0-7 numbered ports. 0 to not retry.
                minPollBmpMode  -   Operating mode that keeps accumulation to a minimum
                				in accordance with the address of the packet that sends
                				the pollBitmap during MP communication.
                singlePacketMode -  Special operating mode where only one packet is sent for
                				one MP.
                fixFreqMode     -   Special operating mode prohibiting increased MP communication by retry.
                                    Frequency of MP communication in one frame is fixed as exactly that of mpFreq.

                ignoreFatalError -  AutoDisconnect will not occur when FatalError occurs.

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_StartMPEx(
    WMCallbackFunc  callback ,
    u16*            recvBuf ,
    u16             recvBufSize ,
    u16*            sendBuf ,
    u16             sendBufSize ,
    u16             mpFreq ,
    u16             defaultRetryCount ,
    BOOL            minPollBmpMode ,
    BOOL            singlePacketMode ,
    BOOL            fixFreqMode ,
    BOOL            ignoreFatalError
)
{
    WMErrCode   result;
    WMArm9Buf*  p = WMi_GetSystemWork();

    // Check state
    result = WMi_CheckStateEx( 2 , WM_STATE_PARENT , WM_STATE_CHILD );
    WM_CHECK_RESULT( result );

    // Confirm MP status
    DC_InvalidateRange( &( p->status->mp_flag ), 4 );    // Disables of ARM7 status area cache.
    if( p->status->mp_flag == TRUE )
    {
        WM_WARNING( "Already started MP protocol. So can't execute request.\n" );
        return WM_ERRCODE_ILLEGAL_STATE;
    }

    //Check parameters
    if( recvBufSize < WM_GetMPReceiveBufferSize() )
    {
        WM_WARNING( "Parameter \"recvBufSize\" is not enough size.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }
    if( (recvBufSize & 0x3f) != 0 ) // recvBufSize/2 must be a multiple of 32 bytes
    {
        WM_WARNING( "Parameter \"recvBufSize\" is not a multiple of 64.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }
    if( sendBufSize < WM_GetMPSendBufferSize() )
    {
        WM_WARNING( "Parameter \"sendBufSize\" is not enough size.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }
    if( (sendBufSize & 0x1f) != 0 ) // sendBufSize must be a multiple of 32 bytes
    {
        WM_WARNING( "Parameter \"sendBufSize\" is not a multiple of 32.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }
    if( (u32)recvBuf & 0x01f )
    {
        // Alignment check issues a warning, not an error
        WM_WARNING( "Parameter \"recvBuf\" is not 32-byte aligned.\n" );
    }
    if( (u32)sendBuf & 0x01f )
    {
        // Alignment check issues a warning, not an error
        WM_WARNING( "Parameter \"sendBuf\" is not 32-byte aligned.\n" );
    }

    // Store the callback function.
    WMi_SetCallbackTable( WM_APIID_START_MP , callback );

    // Notify ARM7 with FIFO
    result = WMi_SendCommand(
        WM_APIID_START_MP , 10 ,
        (u32)recvBuf ,
        (u32)( recvBufSize / 2 ) ,  // Size of one buffer
        (u32)sendBuf ,
        (u32)sendBufSize ,
        (u32)mpFreq ,               // No. of communications
        (u32)defaultRetryCount ,    // Standard number of retries
        (u32)minPollBmpMode ,       // Special operation mode
        (u32)singlePacketMode ,     // Special operation mode
        (u32)fixFreqMode ,          // Special operation mode
        (u32)ignoreFatalError       // Special operation mode
    );
    WM_CHECK_RESULT( result );

    return WM_ERRCODE_OPERATING;
}

/*---------------------------------------------------------------------------*
  Name:         WM_SetMPFrequency

  Description:  Switches how many times to MP communicate per frame. Parent function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.
                mpFreq      -   How many times to MP communicate in one frame.
                                0 for continuous send mode.

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_SetMPFrequency(
    WMCallbackFunc  callback ,
    u16             mpFreq
)
{
    WMErrCode   result;
    WMArm9Buf*  p   = WMi_GetSystemWork();

    // Check state
    result = WMi_CheckState( WM_STATE_MP_PARENT );
    WM_CHECK_RESULT( result );

    // Store the callback function.
    WMi_SetCallbackTable( WM_APIID_SET_MP_FREQ , callback );

    // Notify ARM7 with FIFO
    result = WMi_SendCommand(
        WM_APIID_SET_MP_FREQ , 1 ,
        (u32) mpFreq
    );
    WM_CHECK_RESULT( result );

    return WM_ERRCODE_OPERATING;
}

/*---------------------------------------------------------------------------*
  Name:         WM_SetMPData

  Description:  Reserves data to send in MP communication. Parent/child shared function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.
                sendData    -   Pointer to data that is send-reserved.
                                Note that this data is force cache stored.
                sendDataSize -  size of data to send-reserve.
                tmptt       -   Sets PM packet send time when consecutive send mode.
                                (Only valid for parents.) (07/26/2004, ignore at present)
                pollbmp     -   When consecutive send mode, specifies Poll map showing send target child.

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_SetMPData( WMCallbackFunc callback , const u16* sendData , u16 sendDataSize , u16 tmptt , u16 pollbmp )
{
#pragma unused( tmptt )
    return WM_SetMPDataToPortEx( callback, NULL, sendData, sendDataSize, pollbmp, WM_PORT_RAWDATA, WM_PRIORITY_NORMAL );
}

/*---------------------------------------------------------------------------*
  Name:         WM_SetMPDataToPortEx

  Description:  Reserves data to send with MP communication. Parent/child shared function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.
                arg         -   argument passed to callback
                sendData    -   Pointer to send reserved data.
                                Note that this data is forcibly cache stored.
                sendDataSize -  The size of the send-reserved data.
                destBitmap  -   Specifies the aid bitmap showing the send target child.
                port        -   Send port number.
                prio        -   Priority (0: maximum to 3:minimum)

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_SetMPDataToPortEx( WMCallbackFunc callback, void* arg, const u16* sendData, u16 sendDataSize, u16 destBitmap, u16 port, u16 prio )
{
    WMErrCode   result;
    int         maxSendSize;
    BOOL        isParent;
    u16         mpReadyBitmap = 0x0001;
    u16         childBitmap = 0x0001;
    WMArm9Buf*  p   = WMi_GetSystemWork();

    // Check state
    result = WMi_CheckStateEx( 2 , WM_STATE_MP_PARENT , WM_STATE_MP_CHILD );
    WM_CHECK_RESULT( result );

    // Get the required data from the WMStatus structure
    DC_InvalidateRange( &( p->status->maxSendSize ) , 2 );
    maxSendSize = p->status->maxSendSize;
    DC_InvalidateRange( &( p->status->aid ) , 2 );
    isParent = ( p->status->aid == 0 ) ? TRUE : FALSE;
    if ( isParent == TRUE )
    {
        DC_InvalidateRange( &( p->status->child_bitmap ) , 2 );
        childBitmap = p->status->child_bitmap;
        DC_InvalidateRange( &( p->status->mp_readyBitmap ) , 2 );
        mpReadyBitmap = p->status->mp_readyBitmap;
    }

    //Check parameters
    if( sendData == NULL )
    {
        WM_WARNING( "Parameter \"sendData\" must not be NULL.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }
    if( childBitmap == 0 )
    {
        WM_WARNING( "There is no child connected.\n" );
        return WM_ERRCODE_NO_CHILD;
    }
    if( (u32)sendData & 0x01f )
    {
        // Alignment check issues a warning rather than an error.
        WM_WARNING( "Parameter \"sendData\" is not 32-byte aligned.\n" );
    }
    DC_InvalidateRange( &( p->status->mp_sendBuf ) , 2 );
    if ( (void*)sendData == (void*)p->status->mp_sendBuf )
    {
        WM_WARNING( "Parameter \"sendData\" must not be equal to the WM_StartMP argument \"sendBuf\".\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }

    // Check the transmission size.
    if( sendDataSize + (isParent ? WM_HEADER_PARENT_MAX_SIZE : WM_HEADER_CHILD_MAX_SIZE) > maxSendSize )
    {
        WM_WARNING( "Parameter \"sendDataSize\" is over limit.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }

    if( sendDataSize == 0 )
    {
        WM_WARNING( "Parameter \"sendDataSize\" must not be 0.\n" );
        return WM_ERRCODE_INVALID_PARAM;
    }

    // Write to the specified buffer cache.
    DC_StoreRange( (void*)sendData , sendDataSize );

    // No need to store the callback function.

    // Notify ARM7 with FIFO
    result = WMi_SendCommand(
        WM_APIID_SET_MP_DATA , 7 ,
        (u32)sendData ,
        (u32)sendDataSize ,
        (u32)destBitmap ,
        (u32)port ,
        (u32)prio ,
        (u32)callback ,
        (u32)arg
    );
    WM_CHECK_RESULT( result );

    return WM_ERRCODE_OPERATING;
}

/*---------------------------------------------------------------------------*
  Name:         WM_SetMPDataToPort

  Description:  Reserves the data to send with MP communication. Parent/child shared function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.
                sendData    -   Pointer to data to send-reserve.
                                Note that this data is forcibly cache stored.
                sendDataSize -  Size of the data to send-reserve.
                destBitmap  -   Specifies the aid bitmap showing send destination child.
                port        -   Port number to send.
                prio        -   Priority (0: maximum to 3: minimum)

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_SetMPDataToPort( WMCallbackFunc callback, const u16* sendData, u16 sendDataSize, u16 destBitmap, u16 port, u16 prio )
{
    return WM_SetMPDataToPortEx( callback, NULL, sendData, sendDataSize, destBitmap, port, prio );
}

/*---------------------------------------------------------------------------*
  Name:         WM_EndMP

  Description:  Stops MP communication. Parent/child shared function.

  Arguments:    callback    -   The callback function called when asynchronous process ends.

  Returns:      WMErrCode   -   Returns process results. WM_ERRCODE_OPERATING is returned
  					when an asynchronous process started normally. After that, asynchronous
                                	process results are again passed to callback.
 *---------------------------------------------------------------------------*/
WMErrCode
WM_EndMP( WMCallbackFunc callback )
{
    WMErrCode   result;
    WMArm9Buf*  p   = WMi_GetSystemWork();

    // Check state
    result = WMi_CheckStateEx( 2 , WM_STATE_MP_PARENT , WM_STATE_MP_CHILD );
    WM_CHECK_RESULT( result );

    // Confirm MP status
    DC_InvalidateRange( &( p->status->mp_flag ), 4 );
    if( p->status->mp_flag == FALSE )
    {
        WM_WARNING( "It is not MP mode now.\n" );
        return WM_ERRCODE_ILLEGAL_STATE;
    }

    // Store the callback function.
    WMi_SetCallbackTable( WM_APIID_END_MP , callback );

    // Notify ARM7 with FIFO
    result = WMi_SendCommand( WM_APIID_END_MP , 0 );
    WM_CHECK_RESULT( result );

    return WM_ERRCODE_OPERATING;
}

/*---------------------------------------------------------------------------*
    End of file
 *---------------------------------------------------------------------------*/
