/*=============================================================================

  FILE: OEMOS.c
  
    SERVICES: OEM Functions for OEM Operating System
    
      GENERAL DESCRIPTION:
      A sample implementation of the OEMOS functions declared in
      OEMOS.h that are used in the implementation of AEEFile.
      
        PUBLIC CLASSES AND STATIC FUNCTIONS:
        
          OEMOS_GetUpTime
          OEMOS_GetLocalTimeMS
          OEMOS_SetTimer
          OEMOS_Sleep
          OEMOS_SignalDispatch
          OEMOS_CancelDispatch
          OEMOS_BrewHighPriority
          OEMOS_BrewNormalPriority
          OEMOS_ActiveTaskID
          
            INITIALIZATION AND SEQUENCING REQUIREMENTS:
            No additional module-level initialization or sequencing requirements.
            
              Copyright © 1999-2002 QUALCOMM Incorporated.
              All Rights Reserved.
              QUALCOMM Proprietary/GTDR
=============================================================================*/

#ifdef AEE_SIMULATOR
#include <windows.h>
#endif

#include <stdlib.h>

#if !defined(AEE_SIMULATOR)
# include "customer.h"
#endif

#include "OEMFeatures.h"

#if !defined(AEE_SIMULATOR)
# include "ui.h"
# include "dog.h"

# if defined(FEATURE_USE_TIME_VU)
#  include "timetick.h"
#  include "time_svc.h"
# endif /* #if defined(FEATURE_USE_TIME_VU) */
  
# endif /* #if !defined(AEE_SIMULATOR) */

#include "rex.h"
#include "qw.h"
#include "clki.h"
#include "err.h"

#include "OEMOS.h"
#include "AEEComdef.h"
#include "AEEError.h"
#include "AEEOS.h"

#if defined(FEATURE_PMIC_RTC)
#include "clkrtc.h"
#endif

#if defined (FEATURE_CDMA_800) || defined (FEATURE_CDMA_1900)
#include "db.h"
#endif
#if defined (T_MSM6050) || defined (T_MSM6250) 
#include "sys.h"
#endif 

#define MS_PER_DAY  86400000

/*=================================================================
** LOCAL DEFINES
**===============================================================*/
#define BREW_HI_PRIORITY (900)

#ifdef AEE_SIMULATOR

# define AEE_APP_SIG         1
#ifdef FEATURE_BREW_NET_SIG
# define AEE_NET_SIG         4
#endif
# define AEE_SLEEP_SIG       2
# define AEE_DOG_BIT         1
# define dog_report(x)       0

#else /* #ifdef AEE_SIMULATOR */

# ifndef AEE_APP_SIG
#  define AEE_APP_SIG  UI_APP_SIG
# endif /* # ifndef AEE_APP_SIG */

#ifdef FEATURE_BREW_NET_SIG
# ifndef AEE_NET_SIG
#  define AEE_NET_SIG  UI_NET_SIG
# endif /* # ifndef AEE_NET_SIG */
#endif

# ifndef AEE_DOG_BIT
#  define AEE_DOG_BIT  DOG_UI_RPT
# endif  /* #ifndef AEE_DOG_BIT */

#endif /* #ifdef AEE_SIMULATOR */


/*=================================================================
** FILE SCOPED VARIABLES
**===============================================================*/
static rex_tcb_type      *gptcbAEE;
static rex_priority_type  normal_priority;

/*==================================================================
Function: OEMOS_InitLayer

  Description: Gets started after a call to AEE_Init to allow OEM
  layer code to do anything required to provide services.
  Returns 0 for a successful initialization or any other 
  value to indicate error, in which case AEE will not be
  started.
==================================================================*/
int16  OEMOS_InitLayer() 
{
   gptcbAEE = rex_self();

   normal_priority = rex_get_pri();
   SETSTACKBOTTOM(gptcbAEE->stack_limit);
   
   return AEE_SUCCESS;
}

/*==================================================================
Function: OEMOS_GetUpTime

  Description: Returns time in ms since the device started.
==================================================================*/
uint32 OEMOS_GetUpTime()
{
#if defined(AEE_SIMULATOR)
   
   /* simplest implementation, should work on any version of DMSS,
      but can be *very* slow, and on TIMETICK targets, may jitter */
   
   qword ts;
   
   clk_uptime_ms(ts);
   
   return qw_lo(ts);

#elif defined(FEATURE_USE_TIME_VU)
   qword ts;

   time_get_uptime_ms(ts);
   
   return qw_lo(ts);

#else /* !defined(FEATURE_USE_TIME_VU) && !defined(AEE_SIMULATOR) */

  /* read the clock out of global clk_uptime_val, super fast */

   uint32 secs,ms;
   volatile clk_uptime_type *p_clk_uptime_val;
   
   p_clk_uptime_val = &clk_uptime_val;

   /* loop obviates need for INTLOCK */
   do {
      secs = p_clk_uptime_val->secs;
      ms   = p_clk_uptime_val->ms;
   } while (secs != p_clk_uptime_val->secs);

   return (secs * 1000) + ms;
#endif
}


/*==================================================================
Function: OEMOS_GetLocalTime

  Description: Returns the current local time in sec since 1/6/1980.
  
==================================================================*/
uint32 OEMOS_GetLocalTime() 
{
   return (OEMOS_GetUTCSeconds() + OEMOS_LocalTimeOffset(0));
}


/*==================================================================
Function: OEMOS_GetUTCSeconds

  Description: Returns the current UTC time in sec since 00:00:00 1/6/1980.
  
==================================================================*/
uint32 OEMOS_GetUTCSeconds() 
{
     uint32 systime=0;

#if defined (FEATURE_PMIC_RTC)
  clk_julian_type julian_time;
#endif

#if defined(FEATURE_PMIC_RTC)
  clk_rtc_get_time(&julian_time);
  systime = clk_julian_to_secs(&julian_time);
#else
  qword  ts;
  uint64 secs;
  // NOTE: Please avoid using clk_read_secs, since it returns the current 
  // value of the time-of-day clock rounded to the nearest second. This will
  // cause some trouble to Java since Java is using both GETTIMESECONDS and 
  // GETIMEMS to calculate the number of milli-seconds since UTC and Java 
  // does not know that GETTIMESECONDS has been rounded up.
  clk_read_ms (ts);
  secs  = QW_CVT_Q2N (ts)/1000;
  systime = (uint32) secs;
#endif

  return (systime);

}

/*==================================================================
Function: OEMOS_GetTimeMS

  Description: Returns the number of msec since midnight.
  
==================================================================*/
uint32  OEMOS_GetTimeMS() 
{
   
  qword ts;
  uint64 ms;
   
  clk_read_ms(ts);
  ms = QW_CVT_Q2N (ts);

  ms += (uint64) (LOCALTIMEOFFSET (NULL) * 1000); // no daylight saving
  return ((uint32) (ms % MS_PER_DAY));
   
}

/*==================================================================
Function: OEMOS_JulianToSeconds

  Description: Returns seconds equivalent of specified julian date
==================================================================*/
uint32  OEMOS_JulianToSeconds(JulianType* pDate) 
{
   clk_julian_type ts;
   
   ts.day = pDate->wDay;
   ts.day_of_week = pDate->wWeekDay;
   ts.hour = pDate->wHour;
   ts.minute = pDate->wMinute;
   ts.second = pDate->wSecond;
   ts.month = pDate->wMonth;
   ts.year = pDate->wYear;
   
   return (clk_julian_to_secs(&ts));
}
/*==================================================================
Function: OEMOS_SetTimer

  Description: Sets a master timer for BREW libraries.  Should
  supercede any previous calls to OEMOS_SetTimer.
  A call to OEMOS_SetTimer with a value of zero shall
  cancel any previously set timer.  When the timer set
  expires, AEE_Dispatch should be called.
  
  OEMOS_SetTimer() schedules a ONE-SHOT timer

==================================================================*/
void OEMOS_SetTimer(uint32 nMSecs) 
{
   static clk_cb_type t = {0};

   // Deregister any pending timer and reset the timer for the required 
   // number of milliseconds...
   clk_dereg(&t);

   if (0 != nMSecs) {
      clk_reg(&t, (void (*)(int4))OEMOS_SignalDispatch, nMSecs, 0, FALSE );
   }

}

/*==================================================================
Function: OEMOS_Sleep

  Description: Delays execution of subsequent code for nMsecs.
==================================================================*/
void OEMOS_Sleep(uint32 nMSecs) // period for timer in milliseconds
{
   rex_sigs_type   sigs = 0;
   rex_timer_type  timer;

   if (rex_self() != gptcbAEE) {
      DBGPRINTF("OEMOS_Sleep() called from an unknown task");
      return;
   }

   // initialize a timer
   rex_def_timer(&timer, gptcbAEE, AEE_SLEEP_SIG);

   while (0 != nMSecs) {
      uint32 nInc;

      // kick the dog
      dog_report(AEE_DOG_BIT);

      // Save and clear all our sigs
      sigs |= rex_clr_sigs(gptcbAEE,(rex_sigs_type)-1);
 
      // kick the dog every 10 seconds...
      nInc = MIN(10000, nMSecs);

      rex_clr_timer(&timer);
      rex_timed_wait(AEE_SLEEP_SIG, &timer, nInc);
      rex_clr_sigs(gptcbAEE, AEE_SLEEP_SIG);

      nMSecs -= nInc;
   }

   //Clear the timer explicitly because REX doesn't seem to do it
   rex_clr_timer(&timer);

   // Restore the sigs...
   if (sigs) {
      rex_set_sigs(gptcbAEE, sigs);
   }

}

/*==================================================================
Function: OEMOS_SignalDispatch

  Description: Signals the OEM layer to call AEE_Dispatch from a
  standard context (ie non-ISR or async signal) at the
  next available time.
==================================================================*/
void OEMOS_SignalDispatch(void)
{
   rex_set_sigs(gptcbAEE, AEE_APP_SIG);
}

/*==================================================================
Function: OEMOS_NetSignalDispatch
 
  Description: Signals the OEM layer to call OEMNet_SignalHandler from a
  standard context (ie non-ISR or async signal) at the
  next available time.
==================================================================*/
#ifdef FEATURE_BREW_NET_SIG
void OEMOS_NetSignalDispatch(void)
{
   rex_set_sigs(gptcbAEE, AEE_NET_SIG);
}
#endif

/*=================================================================
Function: OEMOS_CancelDispatch

  Description: Cancel any pending dispatch called by
  OEMOS_SignalDispatch().  If there is no pending
  dispatch operation, this function should do nothing.
=================================================================*/
void OEMOS_CancelDispatch() 
{
   rex_clr_sigs(gptcbAEE, AEE_APP_SIG);
}

/*================================================================
Function: OEMOS_BrewHighPriority

  Description: Sets BREW to be a high priority task.  This means
  that any work BREW has to do will be executed before
  most of the other tasks.   Which tasks BREW should
  be higher or lower than is OEM-dependant.
================================================================*/
void OEMOS_BrewHighPriority() 
{
#ifndef AEE_SIMULATOR
   rex_priority_type nPri;
   nPri = rex_set_pri(BREW_HI_PRIORITY);
   if (nPri != BREW_HI_PRIORITY) {
      normal_priority = nPri;
   }
#endif /* AEE_SIMULATOR */
}

/*================================================================
Function: OEMOS_BrewNormalPriority

  Description: Returns BREW's task to its original priority value
  before OEMOS_BrewHighPriority was called.
================================================================*/
void OEMOS_BrewNormalPriority() 
{
#ifndef AEE_SIMULATOR
   rex_set_pri(normal_priority);
#endif /* AEE_SIMULATOR */
}


#if defined (T_MSM6050) || defined (T_MSM6250) 
sys_sys_mode_e_type OEM_SysMode (void)
{
#if defined(FEATURE_CDMA_800) || defined(FEATURE_CDMA_1900)
#if defined(FEATURE_GSM) || defined(FEATURE_WCDMA)
  /* GSM/1x Multimode targets */
  sys_sys_mode_e_type sys_mode = sd_misc_get_curr_acq_sys_mode();

  if( sys_mode == SYS_SYS_MODE_GSM || sys_mode == SYS_SYS_MODE_WCDMA )
  {
     return SYS_SYS_MODE_GSM;
  }
  else
     return SYS_SYS_MODE_CDMA;
#else
  /* 1x targets */
  return SYS_SYS_MODE_CDMA;
#endif
#else
  /* UMTS targets */
  return SYS_SYS_MODE_GSM;
#endif
}
#endif

/*===============================================================
Function: OEMOS_ActiveTaskID

  Description: Returns a unique identifier to the currently running
  task.  This call is used so that BREW can determine
  it's own task ID as well as conditions where it may
  be called from another task.
===============================================================*/
uint32 OEMOS_ActiveTaskID ()
{
   return (uint32)rex_self();
}        

/*==============================================================
Function: OEMOS_LocalTimeOffset

  Description: Returns the local timezone offset from UTC, in 
  seconds. Optionally returns a flag indicating that 
  daylight savings time is active (if it is, the value 
  of the local timezone offset already takes the shift
  into account; the flag is just for controlling display
  of a timezone name if desired).  The returned value 
  is added to UTC to give local time, or subtracted 
  from local time to give UTC time.
==============================================================*/
int32 OEMOS_LocalTimeOffset 
(
  boolean *bDaylightSavings 
) 
{
   
#ifndef AEE_SIMULATOR
/* We cannot return 0 if FEATURE_PMIC_RTC is defined. Commenting out the
** feature definition will make this function work in CDMA mode. It still
** needs to be fixed for GSM and WCDMA mode.
*/
// #ifndef FEATURE_PMIC_RTC
#if defined (T_MSM6050) || defined (T_MSM6250) 
  if (OEM_SysMode() == SYS_SYS_MODE_CDMA) {
#else
  {
#endif
#if defined (FEATURE_CDMA_800) || defined (FEATURE_CDMA_1900)
   int32                tzoffset;
   db_items_value_type  db_item;
   int                  ltm_off;
   
   //Get the local timezone offset
   db_get(DB_LTM_OFF, &db_item);
   
   ltm_off = (int32)(db_item.ltm_off & 0x3f);
   if (ltm_off  >= 32) 
      ltm_off -= 64;
   
   /* promote timezone offset to seconds from 30 minute units */           
   
   tzoffset = 60 * 30 * ( ltm_off ); /*lint !e737 */             
   
   if (bDaylightSavings) {
      //Get daylight savings time flag
      db_get(DB_DAYLT, &db_item);
      *bDaylightSavings = (boolean)db_item.daylt;
   }
   
   return (tzoffset);
#endif /* FEATURE_CDMA_800 || FEATURE_CDMA_1900 */
  }
// #endif /* !FEATURE_PMIC_RTC */

  return (0); // no offset for RTC targets
   
#else //AEE_SIMULATOR
   
   TIME_ZONE_INFORMATION   lpTimeZone;
   
   if(GetTimeZoneInformation(&lpTimeZone) == TIME_ZONE_ID_DAYLIGHT){
      if(bDaylightSavings)
         *bDaylightSavings = TRUE;
      return(-60 * (lpTimeZone.Bias + lpTimeZone.DaylightBias));
   }
   
   if(bDaylightSavings)
      *bDaylightSavings = FALSE;
   
   //Need to convert to seconds. Also, BREW ret value is reverse of Windows' 
   //return value. So, negate it,
   return(-60 * lpTimeZone.Bias);
   
#endif
}


void OEMOS_ResetDevice(char * pszMsg, uint32 nCause)
{
   ERR_FATAL(pszMsg, nCause, 0, 0);
}

void OEMOS_Breakpoint(uint32 dwType, void * pData, uint32 nSize)
{
   // You can ASSERT here for debug builds if you wish...
   // For now this will only print a debug message to show proper usage
   // of the incoming parameters.
   switch(dwType){
   case AEEBRK_MEMLEAK:
   case AEEBRK_IFACELEAK:
      {
         AEEAppLeak * pal = (AEEAppLeak *)pData;

         if( pal && nSize == sizeof(AEEAppLeak) ){
            char szBuff[64];

            *szBuff = 0;
            AEE_GetMemGroupName(pal->dwMemGroup, szBuff, sizeof(szBuff));
            DBGPRINTF("BPOINT Type %d, %s 0x%p %s", dwType, 
                        (dwType == AEEBRK_MEMLEAK ? "Node" : "IFace"), 
                        pal->pBuffer, szBuff);
         }
      }
      break;
   case AEEBRK_EXCEPTION:
      {
         AEEExceptionType * pet = (AEEExceptionType *)pData;

         if( pet && nSize ){
            DBGPRINTF("BPOINT Type %d, Exception: %d", dwType, *pet);
         }
      }
      break;
   case AEEBRK_CORRUPTNODE:
      {
         DBGPRINTF("BPOINT Type %d, Address: 0x%p", dwType, pData);
         // Determine if you want to walk the heap with AEEkHeap_Walk()
      }
      break;
   default:
      {
         DBGPRINTF("BPOINT Unknown!");
      }
      break;
   }
}
