;===============================================================================
;                               SPLat Controls.                                ;
;                          Product Development Group                           ;
;                            Melbourne,  AUSTRALIA                             ;
;===============================================================================
;PURPOSE:
; A collection of utilities
;
;===============================================================================
;===============================================================================
;           Copyright (c) 2014 SPLat Controls. All rights reserved.            ;
;                                                                              ;
;        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SPLat Controls.        ;
;               The copyright notice above does not evidence any               ;
;              actual or intended publication of such source code.             ;
;===============================================================================

;===============================================================================
;
;<INITSEG>
;
;===============================================================================


;===============================================================================
;
;<CONSTSEG>
;
;===============================================================================
;Compare result
CMPkXeqY          EQU   0
CMPkXgtY          EQU   1
CMPkXltY          EQU   2


;===============================================================================
;
;<MEQUSEG>
;RAM storage
;
;===============================================================================


;===============================================================================
;
;<IOSEG>
;I/O Assignments
;
;===============================================================================


;===============================================================================
;
;AUTOMATIC RAM
;
;===============================================================================
;<DEF_SEM>

;<DEF_BYTE>

;<DEF_WORD>

;<DEF_TIME24>

;<DEF_FLOAT>

;<DEF_BLOCK>


;===============================================================================
;
;<CODESEG>
;
;===============================================================================

;===============================================================================
;DESCRIPTION:
; A helper the allows a subroutine to return using a goto, eg "GoIfXlt 3,Return"
;PARAMETERS:
;  -> Nil
;RETURNS:
; <-  Nil
;===============================================================================
Return:
   Return


;===============================================================================
;DESCRIPTION:
; Calculates Q % W = W
;PARAMETERS:
;  -> Q: number (clobbered)
;  -> W: divisor
;RETURNS:
; <-  W: result
;===============================================================================
fMod:
   QtoU           4                                      ;save
   WtoU           8                                      ;save
   GoSub          fIntDiv
   UtoQ           8                                      ;get original W
   fMul
   UtoQ           4
   fSub                                                  ;calc remainder
   Return


;===============================================================================
;DESCRIPTION:
; Calculates (int)(Q / W) = W
;PARAMETERS:
;  -> Q: number (clobbered)
;  -> W: divisor
;RETURNS:
; <-  W: result
;===============================================================================
fIntDiv:
   fDiv
   WtoU           0                                      ;temp save
   fAbs
   fLoadQ         0.5
   fGoIfWgeQ      _fIntDoAdj
   fLoadW         0.0
   Return
_fIntDoAdj
   UtoW           0
   fGoIfNeg       _fInfDoUnRound                         ;round down as..
   fLoadQ         -0.5
_fInfDoUnRound
   fAdd                                                  ;..fixToU will round up, thus U will contain the integer
   fixToU         0
   floatFromU     0
   Return


;===============================================================================
;DESCRIPTION:
; This function rounds a number to the nearest whole divisor.  For example:
;  Parameters:
;  w = 157
;  q = -20
;  Result:
;  w = 160
;  q = -20
; This is useful in the UI when changing from a small step size to a large step
; size because a button has been long held.  It looks odd if a number sequence
; does this:
;  159, 158, 157, 137, 117, 97...
; better to do this:
;  159, 158, 157, 140, 120, 100...
;PARAMETERS:
;  -> w:value
;  -> q:step size
;RETURNS:
; <-  w:rounded value
; <-  q:unchanged
;===============================================================================
fIntRound:
   QtoU           4                                   ;save step
   fSwap
   fAbs                                               ;remove sign confusion
   GoSub          fIntDiv                             ;calc value/step removing decimal
   fWtoQ                                              ;scale..
   UtoW           4
   fAbs
   fMul                                               ;..back up
   UtoQ           4                                   ;restore step size
   Return


;===============================================================================
;DESCRIPTION:
; Saves the NV pointers (uses UV registers)
;PARAMETERS:
;  -> Nil
;RETURNS:
; <-  Nil
;===============================================================================
NVSavePtrs:
   WtoU           7                                   ;save W
   NVfGetPtrW
   WtoU           0
   NVPushRecLen
   PopU           4
   NVPushRecNum
   PopU           5
   NVPushPage
   PopU           6
   UtoW           7                                   ;restore W
   Return


;===============================================================================
;DESCRIPTION:
; Restores the NV pointers following a call to NVSavePtrs
;PARAMETERS:
;  -> Nil
;RETURNS:
; <-  Nil
;===============================================================================
NVRestorePtrs:
   WtoU           7                                   ;save W
   PushU          6
   NVPopPage
   UtoW           0
   NVfPutPtrW
   PushU          4
   NVPopRecLen
   PushU          5
   NVPopRecNum
   UtoW           7                                   ;restore W
   Return


;===============================================================================
;DESCRIPTION:
; This routine is used to smooth a new reading.  The equation is:
;  SmoothedValue = NewReading * Smoothing + SmoothedValue * (1.0 - Smoothing)
; Usage:
;  fMyVar   defFLOAT ;filtered reading
;
;  fAnIn    0        ;new reading in W
;  fLoadQ   0.1      ;smoothing const
;  LoadI    fMyVar
;  GoSub    fFilter  ;fMyVar contains old and new reading
;PARAMETERS:
;  -> w: new reading
;  -> q: smoothing constant (0.1 means use 1/10th of the new reading and 0.9 of
;  existing smoothed value)
;  -> i: smoothed variable float address
;RETURNS:
; <-  Nil
;===============================================================================
fFilter:
   fMul                                               ;calc part of new reading, FracNew = New * Smoothing
   WtoU           4                                   ;save
   fLoadW         1.0
   fSwap
   fSub                                               ;calc InvSmoothing = 1.0 - Smoothing
   GoSub          ipfRecallQ                          ;read the current filter variable
   fMul                                               ;calc FracFilter = Filter * InvSmoothing
   UtoQ           4
   fAdd                                               ;calc NewFilt = FracFilter + FracNew
   GoSub          ipfStoreW                           ;write back to the filter variable
   Return


;===============================================================================
;DESCRIPTION:
; This function fetches the floating point varaible from an address pointed to by
; i.  This differs from ifRecallW which calculates the varaible address
; as: BaseAddr + i * 4.
;PARAMETERS:
;  -> i: floating point varaible address
;RETURNS:
; <-  W: floating point value
;===============================================================================
ipfRecallW:
   GoSub          subifRecall                         ;place the varaible in u[0-3]
   UtoW           0                                   ;copy to W
   Return


;===============================================================================
;DESCRIPTION:
; This function fetches the floating point varaible from an address pointed to by
; i.  This differs from ifRecallW which calculates the varaible address
; as: BaseAddr + i * 4.
;PARAMETERS:
;  -> i: floating point varaible address
;RETURNS:
; <-  W: floating point value
;===============================================================================
ipfRecallQ:
   GoSub          subifRecall                         ;place the varaible in u[0-3]
   UtoQ           0                                   ;copy to Q
   Return

subifRecall
   iRecall        0                                   ;load the..
   PopU           0
   iRecall        1
   PopU           1
   iRecall        2
   PopU           2
   iRecall        3
   PopU           3
   Return


;===============================================================================
;DESCRIPTION:
; This function stores the floating point varaible to an address pointed to by
; i.  This differs from ifStore which calculates the varaible address
; as: BaseAddr + i * 4.
;PARAMETERS:
;  -> i: floating point varaible address
;  -> W: floating point value
;RETURNS:
; <-  nil
;===============================================================================
ipfStoreW:
   WtoU           0                                   ;copy W to U
   Goto           subipfStore                         ;place u[0-3] to the variable


;===============================================================================
;DESCRIPTION:
; This function stores the floating point varaible to an address pointed to by
; i.  This differs from ifStore which calculates the varaible address
; as: BaseAddr + i * 4.
;PARAMETERS:
;  -> i: floating point varaible address
;  -> W: floating point value
;RETURNS:
; <-  nil
;===============================================================================
ipfStoreQ:
   QtoU           0                                   ;copy Q to U
   Goto           subipfStore                         ;place u[0-3] to the variable


subipfStore
   PushU          0
   iStore         0
   PushU          1
   iStore         1
   PushU          2
   iStore         2
   PushU          3
   iStore         3
   Return


;===============================================================================
;DESCRIPTION:
; Calculates a polynomial of any order.  The control table format is:
;  NV0Byte     N     ;The order of the polynomial
;  NV0fNum     An    ;The X^n coefficient
;  NV0fNum     An-1  ;The X^(n-1) coefficient
;   ....
;  NVfNum      A1    ;The X coefficient
;  NVfNum      A0    ;The constant
;
; Example:
; The polynomial Y = 1.4 * x^4 - 1.3 * x^3 + 1.2 * x^2 - 1.1 * x  + 1
; is a 4th order polynomial. It's control table would be
;PolyTab:
;  NV0Byte  4     ;Fourth order
;  NV0fNum  1.4   ;Coefficient for x^4
;  NV0fNum  -1.3  ;Coefficient for x^3
;  NV0fNum  1.2   ;Coefficient for x^2
;  NV0fNum  -1.1  ;Coefficient for x^1
;  NV0fNum  1.0   ;Constant
;PARAMETERS:
;  -> W The argument value (normally called X)
;  -> NVEMPtr Control table address
;RETURNS:
; <-  W the y result
;===============================================================================
PolyCalculate:
   WtoU           0                                   ;save argument
   NVSetpage      0
   NVSetRecNum    0
   NVSetRecLen    4
   NVPushByte     0                                   ;get the order of the poly to X
   XtoI
   NVAddPtr       1                                   ;now points to first coefficient
   NVfReadW       0                                   ;get first coefficient
_PolyCalcLoop
   NVAdvPtr                                           ;ready for next time
   UtoQ           0                                   ;argument
   fMul
   NVfReadQ       0                                   ;get next coefficient
   fAdd
   DecI
   GoIfInz        _PolyCalcLoop
   Return


;===============================================================================
;DESCRIPTION:
; Convert a time in seconds to hours:minutes:seconds
;PARAMETERS:
;  -> w:seconds
;RETURNS:
; <-  u[12]:hours, u[13]:minutes, u[14]:seconds
;===============================================================================
subSecondsToHMS:
   ;--hours
   WtoU           16                                  ;temp save
   fWtoQ
   fLoadW         3600                                ;calculate..
   GoSub          fIntDiv                             ;..hours
   fix
   PopU           12                                  ;put into u[12]
   fLoadQ         3600
   fMul                                               ;whole hours back to seconds
   UtoQ           16
   fSub                                               ;calc remaining min:sec
subSecondsToMS:                                       ;result in u[13]:minutes, u[14]:seconds
   ;--minutes
   WtoU           16                                  ;temp save
   fWtoQ
   fLoadW         60                                  ;calculate..
   GoSub          fIntDiv                             ;..minutes
   fix
   PopU           13                                  ;put into u[13]
   fLoadQ         60
   fMul                                               ;whole minutes back to seconds
   UtoQ           16
   fSub                                               ;calc remaining sec
   ;--seconds
   fix
   PopU           14
   Return


;===============================================================================
;
;<DEBUG>
;
;===============================================================================


;===============================================================================
;
;<TESTSEG>
;
;===============================================================================


