/*---------------------------------------------------------------------------*
  Project:  TwlSDK - NWM - libraries
  File:     nwm_system.c

  Copyright 2007-2008 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.

  $Date:: 2008-09-17#$
  $Rev: 8556 $
  $Author: okubata_ryoma $
 *---------------------------------------------------------------------------*/

#include <twl.h>
#include "nwm_arm9_private.h"
#include "nwm_common_private.h"

NWMArm9Buf *nwm9buf = NULL;
static PMSleepCallbackInfo sleepCbInfo;  //Sleep callback information to register with the PM library

#ifdef NWM_SUPPORT_HWRESET
PMExitCallbackInfo hwResetCbInfo;
#endif

static void NwmSleepCallback(void *);

/*---------------------------------------------------------------------------*
  Name:         NWMi_GetSystemWork

  Description:  Gets a pointer to the start of the buffer used internally by the new WM library.

  Arguments:    None.

  Returns:      NWMArm9Buf*: Returns a pointer to the internal work buffer.
 *---------------------------------------------------------------------------*/
NWMArm9Buf *NWMi_GetSystemWork(void)
{
//    SDK_NULL_ASSERT(nwm9buf);
    return nwm9buf;
}


/*---------------------------------------------------------------------------*
  Name:         NWMi_ClearFifoRecvFlag

  Description:  Notifies the new WM7 that access to FIFO data used by a callback from the new WM7 is complete.
                When using a FIFO in a new WM7 callback, wait for this flag to unlock before editing the next callback.
                
                

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/

void NWMi_ClearFifoRecvFlag(void)
{
    NWMArm7Buf *w7b;

    if (nwm9buf == NULL) {
        return;
    }
    
    w7b = nwm9buf->NWM7;

    // The ARM7 will read the updated value, so invalidate the ARM9 cache
    DC_InvalidateRange(&w7b->callbackSyncFlag, 1);
    
    if (w7b->callbackSyncFlag & NWM_EXCEPTION_CB_MASK)
    {
        // Disables the CB exclusion flag
        w7b->callbackSyncFlag &= ~NWM_EXCEPTION_CB_MASK;
        // Store cache immediately
        DC_StoreRange(&w7b->callbackSyncFlag, 1);
    }
}


/*---------------------------------------------------------------------------*
  Name:         NWMi_ReceiveFifo9

  Description:  Receives a callback from the new WM7 through a FIFO.

  Arguments:    tag:            Unused
                fifo_buf_adr:   Pointer to the callback parameter group
                err:            Unused

  Returns:      None.
 *---------------------------------------------------------------------------*/

void NWMi_ReceiveFifo9(PXIFifoTag tag, u32 fifo_buf_adr, BOOL err)
{
    #pragma unused( tag )
    NWMCallback *pCallback = (NWMCallback *)fifo_buf_adr;
    NWMCallbackFunc callback;
    NWMArm9Buf *w9b = nwm9buf;

    if (w9b == NULL) {
        return;
    }
    
    if (err) {
        NWM_WARNING("NWM9 FIFO receive error. :%d\n", err);
        return;
    }

    if (!fifo_buf_adr) {
        NWM_WARNING("NWM9 FIFO receive error.(NULL address) :%d\n", err);
        return;
    }

    DC_InvalidateRange(w9b->fifo7to9, NWM_APIFIFO_BUF_SIZE);
    DC_InvalidateRange(w9b->status, NWM_STATUS_BUF_SIZE);
    if ((u32)pCallback != (u32)(w9b->fifo7to9))
    {
        DC_InvalidateRange(pCallback, NWM_APIFIFO_BUF_SIZE);
    }

    NWM_DPRINTF("APIID%04x\n", pCallback->apiid);

    // Remove the sleep callback if NWM_LoadDevice failed or WM_UnloadDevice succeeded.
    if( (pCallback->apiid == NWM_APIID_LOAD_DEVICE   && pCallback->retcode != NWM_RETCODE_SUCCESS) ||
        (pCallback->apiid == NWM_APIID_UNLOAD_DEVICE && pCallback->retcode == NWM_RETCODE_SUCCESS) ||
         pCallback->apiid == NWM_APIID_INSTALL_FIRMWARE )
    {
        NWMi_DeleteSleepCallback();
    }

    // Callback processing according to apiid (does nothing if callback not set (NULL))
    {
        NWMSendFrameCallback *pSfcb = (NWMSendFrameCallback *)pCallback;
        NWMRetCode result = NWM_RETCODE_FAILED;
        
        if (pCallback->apiid == NWM_APIID_SEND_FRAME)
        {
            if (pCallback->retcode != NWM_RETCODE_INDICATION && NULL != pSfcb->callback)
            {
                NWM_DPRINTF("Execute CallbackFunc APIID 0x%04x\n", pCallback->apiid);
                (pSfcb->callback)((void *)pCallback);
            }

        }
    }

    // In the case of several special APIs
    if (pCallback->apiid == NWM_APIID_SEND_FRAME) {
        NWMSendFrameCallback *pSfcb = (NWMSendFrameCallback *)pCallback;

    } else {

#ifdef NWM_SUPPORT_HWRESET
        if (pCallback->apiid == NWM_APIID_UNLOAD_DEVICE
            || pCallback->apiid == NWM_APIID_INSTALL_FIRMWARE
            || (pCallback->apiid == NWM_APIID_LOAD_DEVICE
                && pCallback->retcode != NWM_RETCODE_SUCCESS)) {
            // Delete HW reset callback
            PM_DeletePostExitCallback(&hwResetCbInfo);
        }
#endif
        
        // Other APIs
        callback = w9b->callbackTable[pCallback->apiid];

        // In case START_SCAN callback, scan buffer cache must be invalidated
        if (pCallback->apiid == NWM_APIID_START_SCAN) {
            NWMStartScanCallback *psscb = (NWMStartScanCallback *)pCallback;

            DC_InvalidateRange(psscb->bssDesc[0], psscb->allBssDescSize);
        }

        if (NULL != callback)
        {
            NWM_DPRINTF("Execute CallbackFunc APIID 0x%04x\n", pCallback->apiid);
            (callback) ((void *)pCallback);
        }

    }

    MI_CpuClear8(pCallback, NWM_APIFIFO_BUF_SIZE);
    DC_StoreRange(pCallback, NWM_APIFIFO_BUF_SIZE);
    if (w9b) { // NWM might be terminated after callback
        NWMi_ClearFifoRecvFlag();
    }

}

/*---------------------------------------------------------------------------*
  Name:         NWM_GetState

  Description:  Checks the internal state of the NWM library.
                The purpose for using this is similar to NWMi_CheckState, but its application is largely different so it is provided separately.
                

  Arguments:    None.

  Returns:      u16: Integer that indicates the internal NWM state
 *---------------------------------------------------------------------------*/
u16 NWM_GetState(void)
{
    NWMStatus*  nwmStatus;
    NWMArm9Buf* sys = NWMi_GetSystemWork();
    u16 state = NWM_STATE_NONE;

    if (sys) {
        nwmStatus = sys->status;
        DC_InvalidateRange(nwmStatus, 2);
        state = nwmStatus->state;
    }

    return state;
}

/*---------------------------------------------------------------------------*
  Name:         NWMi_CheckState

  Description:  Checks the internal state of the NWM library.
                The WMState parameters indicating the allowed states are specified in a list.

  Arguments:    paramNum:        Number of virtual arguments
                ...:        Virtual argument

  Returns:      int: Returns the result of the process as an NWM_RETCODE_* value.
 *---------------------------------------------------------------------------*/
NWMRetCode NWMi_CheckState(s32 paramNum, ...)
{
    NWMRetCode result;
    u16     now;
    u32     temp;
    va_list vlist;
    NWMArm9Buf *sys = NWMi_GetSystemWork();

    SDK_NULL_ASSERT(sys);

    // Check if initialized
    result = NWMi_CheckInitialized();
    NWM_CHECK_RESULT(result);

    // Gets the current state
    DC_InvalidateRange(&(sys->status->state), 2);
    now = sys->status->state;

    // Match confirmation
    result = NWM_RETCODE_ILLEGAL_STATE;
    va_start(vlist, paramNum);
    for (; paramNum; paramNum--)
    {
        temp = va_arg(vlist, u32);
        if (temp == now)
        {
            result = NWM_RETCODE_SUCCESS;
        }
    }
    va_end(vlist);

    if (result == NWM_RETCODE_ILLEGAL_STATE)
    {
        NWM_WARNING("New WM state is \"0x%04x\" now. So can't execute request.\n", now);
    }

    return result;
}

/*---------------------------------------------------------------------------*
  Name:         NWM_GetAllowedChannel

  Description:  Gets the IEEE 802.11b/g channel list that can be used with the new wireless functions.

  Arguments:    None.

  Returns:      u16: Returns a channel bitmap in the same format as the WM library.
 *---------------------------------------------------------------------------*/
u16 NWM_GetAllowedChannel(void)
{
    NWMArm9Buf *sys = NWMi_GetSystemWork();

    return sys->status->allowedChannel;
}

/*---------------------------------------------------------------------------*
  Name:         NWM_CalcLinkLevel

  Description:  Calculates the link level from the threshold value defined in nwm_common_private.h.

  Arguments:    s16: The RSSI value sent with a notification from the Atheros driver

  Returns:      u16: The same link level as the WM library
 *---------------------------------------------------------------------------*/
u16 NWM_CalcLinkLevel(s16 rssi)
{

/* [TODO] Does this need to be switched depending on the operating mode? If this is necessary, the conditional statement must be revised. */

    if(1) /* Infra Structure Mode */
    {
        if(rssi < NWM_RSSI_INFRA_LINK_LEVEL_1)
        {
            return WM_LINK_LEVEL_0;
        }
        if(rssi < NWM_RSSI_INFRA_LINK_LEVEL_2)
        {
            return WM_LINK_LEVEL_1;
        }
        if(rssi < NWM_RSSI_INFRA_LINK_LEVEL_3)
        {
            return WM_LINK_LEVEL_2;
        }

        return WM_LINK_LEVEL_3;
    }
    else if(0) /*Ad Hoc Mode*/
    {
        if(rssi < NWM_RSSI_ADHOC_LINK_LEVEL_1)
        {
            return WM_LINK_LEVEL_0;
        }
        if(rssi < NWM_RSSI_ADHOC_LINK_LEVEL_2)
        {
            return WM_LINK_LEVEL_1;
        }
        if(rssi < NWM_RSSI_ADHOC_LINK_LEVEL_3)
        {
            return WM_LINK_LEVEL_2;
        }
        return WM_LINK_LEVEL_3;
    }

}

/*---------------------------------------------------------------------------*
  Name:         NWM_GetDispersionScanPeriod

  Description:  Gets the time limit that should be set on searching for an AP or DS parent device as an STA.

  Arguments:    u16 scanType: The scan type, either NWM_SCANTYPE_PASSIVE or NWM_SCANTYPE_ACTIVE.
  
  Returns:      u16:    Search limit time that should be set (ms)
 *---------------------------------------------------------------------------*/
u16 NWM_GetDispersionScanPeriod(u16 scanType)
{
    u8      mac[6];
    u16     ret;
    s32     i;

    OS_GetMacAddress(mac);
    for (i = 0, ret = 0; i < 6; i++)
    {
        ret += mac[i];
    }
    ret += OS_GetVBlankCount();
    ret *= 13;
    
    if( scanType == NWM_SCANTYPE_ACTIVE )
    {
        ret = (u16)(NWM_DEFAULT_ACTIVE_SCAN_PERIOD + (ret % 10));
    }
    else /* An unknown scan type is treated in the same way as a passive scan */
    {
        ret = (u16)(NWM_DEFAULT_PASSIVE_SCAN_PERIOD + (ret % 10));
    }
    return ret;
}

/*---------------------------------------------------------------------------*
  Name:         NWMi_RegisterSleepCallback

  Description:  Registers the callback function that will be run when entering Sleep Mode.
  
  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void NWMi_RegisterSleepCallback(void)
{
    PM_SetSleepCallbackInfo(&sleepCbInfo, NwmSleepCallback, NULL);
    PMi_InsertPreSleepCallbackEx(&sleepCbInfo, PM_CALLBACK_PRIORITY_NWM );
}

/*---------------------------------------------------------------------------*
  Name:         NWMi_DeleteSleepCallback

  Description:  Deletes the callback function that is run when entering Sleep Mode.
  
  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void NWMi_DeleteSleepCallback(void)
{
    PM_DeletePreSleepCallback( &sleepCbInfo );
}

/*---------------------------------------------------------------------------*
  Name:         NwmSleepCallback

  Description:  Prevents the program from entering Sleep Mode during wireless communications.
  
  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void NwmSleepCallback(void *)
{
    /* ---------------------------------------------- *
     * As described in section 6.5 of the Programming Guidelines, it is prohibited to run OS_GoSleepMode() during wireless communications
     * 
     * 
     * ---------------------------------------------- */
    OS_Panic("Could not sleep during wireless communications.");
}

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