(*************************************************************************

     $RCSfile: RealTime.mod $
  Description: Interface to realtime.library

   Created by: fjc (Frank Copeland)
    $Revision: 3.1 $
      $Author: fjc $
        $Date: 1994/08/08 01:18:02 $

  Includes Release 40.15

  (C) Copyright 1993 Commodore-Amiga, Inc.
      All Rights Reserved

  Oberon-A Interface Copyright © 1994, Frank Copeland.
  This file is part of the Oberon-A Interface.
  See Oberon-A.doc for conditions of use and distribution.

  Log entries are at the end of the file.

*************************************************************************)

MODULE RealTime;

(*
** $C- CaseChk       $I- IndexChk  $L+ LongAdr   $N- NilChk
** $P- PortableCode  $R- RangeChk  $S- StackChk  $T- TypeChk
** $V- OvflChk       $Z- ZeroVars
*)

IMPORT
  E   := Exec,
  U   := Utility,
  SYS := SYSTEM;

(*
**      $VER: realtime.h 40.3 (5.4.93)
**
**      realtime.library timing and syncing system
*)

(*****************************************************************************)

CONST

(* realtime.library's idea of time is based on a clock which emits a pulse
 * 1200 times a second (1.2kHz). All time values maintained by realtime.library
 * are based on this number. For example, the field RealTimeBase->rtb_Time
 * expresses an amount of time equivalent to (RealTimeBase->rtb_Time/TICK_FREQ)
 * seconds.
 *)
  tickFreq * = 1200;


(*****************************************************************************)

TYPE

(* Each Conductor represents a group of applications which wish to remain
 * synchronized together.
 *
 * This structure must only be allocated by realtime.library and is
 * READ-ONLY!
 *)
  ConductorPtr * = CPOINTER TO Conductor;
  Conductor * = RECORD (E.Node)
    reserved0 *       : E.UWORD;
    players *         : E.MinList; (* this conductor's players      *)
    clockTime *       : E.ULONG;   (* current time of this sequence *)
    startTime *       : E.ULONG;   (* start time of this sequence   *)
    externalTime *    : E.ULONG;   (* time from external unit       *)
    maxExternalTime * : E.ULONG;   (* upper limit on sync'd time    *)
    metronome *       : E.ULONG;   (* MetricTime highest pri node   *)
    reserved1 *       : E.UWORD;
    flags *           : E.WSET;    (* conductor flags               *)
    state *           : E.UBYTE;   (* playing or stopped            *)
  END;

CONST

(* Flag bits for Conductor.cdt_Flags *)
  conductExternal * = 0;       (* clock is externally driven *)
  conductGotTick *  = 1;       (* received 1st external tick *)
  conductMetroSet * = 2;       (* cdt_Metronome filled in    *)
  conductPrivate *  = 3;       (* conductor is private       *)

(* constants for Conductor.cdt_State and SetConductorState() *)
  condStateStopped * = 0;          (* clock is stopped              *)
  condStatePaused *  = 1;          (* clock is paused               *)
  condStateLocate *  = 2;          (* go to 'running' when ready    *)
  condStateRunning * = 3;          (* run clock NOW                 *)

(* These do not actually exist as Conductor states, but are used as additional
 * arguments to SetConductorState()
 *)
  condStateMetric *    = -1;       (* ask high node to locate       *)
  condStateShuttle *   = -2;       (* time changing but not running *)
  condStateLocateSet * = -3;       (* maestro done locating         *)


(*****************************************************************************)

TYPE

(* The Player is the connection between a Conductor and an application.
 *
 * This structure must only be allocated by realtime.library and is
 * READ-ONLY!
 *)
  PlayerPtr * = CPOINTER TO Player;
  Player * = RECORD (E.Node)
    reserved0 *  : SHORTINT;
    reserved1 *  : SHORTINT;
    hook *       : U.HookPtr;     (* player's hook function       *)
    source *     : ConductorPtr;  (* pointer to parent context    *)
    task *       : E.TaskPtr;     (* task to signal for alarm     *)
    metricTime * : LONGINT;       (* current time in app's metric *)
    alarmTime *  : LONGINT;       (* time to wake up              *)
    userData *   : E.APTR;        (* for application use          *)
    playerID *   : E.UWORD;       (* for application use          *)
    flags *      : E.WSET;        (* general Player flags         *)
  END;

CONST

(* Flag bits for Player.pl_Flags *)
  playerbReady * = 0;              (* player is ready to go!        *)
  playerbAlarmSet * = 1;           (* alarm is set                  *)
  playerbQuiet * = 2;              (* a dummy player, used for sync *)
  playerbConducted * = 3;          (* give me metered time          *)
  playerbExtSync * = 4;            (* granted external sync         *)


(*****************************************************************************)

CONST

(* Tags for CreatePlayer(), SetPlayerAttrs(), and GetPlayerAttrs() *)
  playerBase *         = U.tagUser + 64;
  playerHook *         = playerBase+1;   (* set address of hook function *)
  playerName *         = playerBase+2;   (* name of player               *)
  playerPriority *     = playerBase+3;   (* priority of player           *)
  playerConductor *    = playerBase+4;   (* set conductor for player     *)
  playerReady *        = playerBase+5;   (* the "ready" flag             *)
  playerAlarmTime *    = playerBase+12;  (* alarm time (sets PLAYERF_ALARMSET) *)
  playerAlarm *        = playerBase+13;  (* sets/clears PLAYERF_ALARMSET flag  *)
  playerAlarmSigTask * = playerBase+6;   (* task to signal for alarm/notify    *)
  playerAlarmSigBit *  = playerBase+8;   (* signal bit for alarm (or -1) *)
  playerConducted *    = playerBase+7;   (* sets/clears PLAYERF_CONDUCTED flag   *)
  playerQuiet *        = playerBase+9;   (* don't process time thru this *)
  playerUserData *     = playerBase+10;
  playerID *           = playerBase+11;
  playerExtSync *      = playerBase+14;  (* attempt/release to ext sync  *)
  playerErrorCode *    = playerBase+15;  (* error return value           *)


(*****************************************************************************)

CONST

(* Method types for messages sent via a Player's hook *)
  pmTick * = 0;
  pmState * = 1;
  pmPosition * = 2;
  pmShuttle * = 3;

TYPE

  MsgPtr * = CPOINTER TO Msg;
  Msg * = RECORD
    method * : E.ULONG;
  END;

(* used for PM_TICK, PM_POSITION and PM_SHUTTLE methods *)
  PMTimePtr * = CPOINTER TO PMTime;
  PMTime * = RECORD (Msg) (* PM_TICK, PM_POSITION, or PM_SHUTTLE *)
    time * :  E.ULONG;
  END;

(* used for the PM_STATE method *)
  PMStatePtr * = CPOINTER TO PMState;
  PMState * = RECORD (Msg) (* PM_STATE *)
    oldState * :  E.ULONG;
  END;


(*****************************************************************************)

CONST

(* Possible lock types for LockRealTime() *)
  rtConductors * = 0;     (* conductor list *)


(*****************************************************************************)

CONST

(* realtime.library error codes *)
  eNoMemory *    = 801;  (* memory allocation failed      *)
  eNoConductor * = 802;  (* player needs a conductor      *)
  eNoTimer *     = 803;  (* timer (CIA) allocation failed *)
  ePlaying *     = 804;  (* can't shuttle while playing   *)


(*****************************************************************************)

TYPE

(* OpenLibrary("realtime.library",0) returns a pointer to this structure.
 * All fields are READ-ONLY.
 *)
  RealTimeBasePtr * = CPOINTER TO RealTimeBase;
  RealTimeBase * = RECORD (E.Library)
    reserved0 - : ARRAY 2 OF E.UBYTE;

    time -      : E.ULONG;   (* current time                         *)
    timeFrac -  : E.ULONG;   (* fixed-point fraction part of time    *)
    reserved1 - : E.UWORD;
    tickErr -   : INTEGER;   (* nanosecond error from ideal Tick     *)
  END;                       (* length to real tick length           *)

CONST

(* Actual tick length is: 1/TICK_FREQ + rtb_TickErr/1e9 *)

  realTimeTickErrMin * = -705;
  realTimeTickErrMax * = 705;


(*****************************************************************************)

(*-- Library Base variable --------------------------------------------*)

CONST

  name * = "realtime.library";

VAR

  base* : RealTimeBasePtr;


(*-- Library Functions ------------------------------------------------*)

(*
**      $VER: realtime_protos.h 40.1 (16.3.93)
*)

(*--- functions in V37 or higher (Release 2.04) ---*)

(* Locks *)

LIBCALL (base : RealTimeBasePtr) LockRealTime *
  ( lockType [0] : E.ULONG )
  : E.APTR;
  -30;

LIBCALL (base : RealTimeBasePtr) UnlockRealTime *
  ( lock [8] : E.APTR );
  -36;

(* Conductor *)

LIBCALL (base : RealTimeBasePtr) CreatePlayerA *
  ( tagList [8] : ARRAY OF U.TagItem )
  : PlayerPtr;
  -42;

LIBCALL (base : RealTimeBasePtr) CreatePlayer *
  ( tagList [8]..: U.Tag )
  : PlayerPtr;
  -42;

LIBCALL (base : RealTimeBasePtr) DeletePlayer *
  ( player [8] : PlayerPtr );
  -48;

LIBCALL (base : RealTimeBasePtr) SetPlayerAttrsA *
  ( player  [8] : PlayerPtr;
    tagList [9] : ARRAY OF U.TagItem )
  : BOOLEAN;
  -54;

LIBCALL (base : RealTimeBasePtr) SetPlayerAttrs *
  ( player  [8]  : PlayerPtr;
    tagList [9]..: U.Tag )
  : BOOLEAN;
  -54;

LIBCALL (base : RealTimeBasePtr) SetConductorState *
  ( player [8] : PlayerPtr;
    state [0]  : E.ULONG;
    time [1]   : LONGINT )
  : LONGINT;
  -60;

LIBCALL (base : RealTimeBasePtr) ExternalSync *
  ( player  [8] : PlayerPtr;
    minTime [0] : LONGINT;
    maxTime [1] : LONGINT )
  : BOOLEAN;
  -66;

LIBCALL (base : RealTimeBasePtr) NextConductor *
  ( previousConductor [8] : ConductorPtr )
  : ConductorPtr;
  -72;

LIBCALL (base : RealTimeBasePtr) FindConductor *
  ( name [8] : ARRAY OF CHAR )
  : ConductorPtr;
  -78;

LIBCALL (base : RealTimeBasePtr) GetPlayerAttrsA *
  ( player  [8] : PlayerPtr;
    tagList [9] : ARRAY OF U.TagItem )
  : E.ULONG;
  -84;

LIBCALL (base : RealTimeBasePtr) GetPlayerAttrs *
  ( player  [8]  : PlayerPtr;
    tagList [9]..: U.Tag )
  : E.ULONG;
  -84;

(*-- Library Base variable --------------------------------------------*)
(* $L- *)

(*-----------------------------------*)
PROCEDURE* CloseLib ();

BEGIN (* CloseLib *)
  IF base # NIL THEN E.base.CloseLibrary (base) END
END CloseLib;

(*-----------------------------------*)
PROCEDURE OpenLib * (mustOpen : BOOLEAN);

BEGIN (* OpenLib *)
  IF base = NIL THEN
    base :=
      SYS.VAL (
        RealTimeBasePtr,
        E.base.OpenLibrary (name, E.libraryMinimum));
    IF base # NIL THEN SYS.SETCLEANUP (CloseLib)
    ELSIF mustOpen THEN HALT (100)
    END;
  END;
END OpenLib;

BEGIN
  base := NIL
END RealTime.
