// GateConUser.bcpl -- talks to the Gateway control process

// Last modified March 6, 1979  10:44 PM by Boggs

get "Pup0.decl"
get "Pup1.decl"
get "GateConServ.decl"

external
[
// outgoing procedures
CreateGateConCtx; GateConVersion; GateConSummary
RestartGateway; HaltGateway; RestartGateConUser

// incoming procedures
OpenLevel1Socket; CloseLevel1Socket; GetBuf; ReleasePBI
Zero; MoveBlock; Allocate; Free; Enqueue
ReadCalendar; DoubleSubtract; Divide32x16
InitializeContext; Block; SetTimer; TimerHasExpired
Ws; Wss; PutTemplate; Confirm
SendCommand

// incoming statics
sysZone; ctxQ; gcNet; gcHost; gcName; oldStatsQ
]

static @gcu

structure GCU:		// gcu -> this 'global frame' for Gate Control User
[
soc word		// -> PupSoc
stats word		// -> GateControl Stats block
timer word		// update stats when this expires
]
manifest lenGCU = size GCU/16

//----------------------------------------------------------------------------
let CreateGateConCtx() be
//----------------------------------------------------------------------------
[
Enqueue(ctxQ, InitializeContext(Allocate(sysZone, 150), 150, GateConCtx))
gcu = Allocate(sysZone, lenGCU); Zero(gcu, lenGCU)
gcu>>GCU.soc = Allocate(sysZone, lenPupSoc); OpenLevel1Socket(gcu>>GCU.soc)
]

//----------------------------------------------------------------------------
and RestartGateConUser() be
//----------------------------------------------------------------------------
[
SetTimer(lv gcu>>GCU.timer, 0)
if gcu>>GCU.stats ne 0 then
   [ Enqueue(oldStatsQ, gcu>>GCU.stats); gcu>>GCU.stats = 0 ]
]

//----------------------------------------------------------------------------
and GateConCtx(ctx) be  //a context
//----------------------------------------------------------------------------
[
Block() repeatuntil TimerHasExpired(lv gcu>>GCU.timer) & gcHost ne 0
SetTimer(lv gcu>>GCU.timer, 500)
let pbi = SendCommand(GetBuf(gcu>>GCU.soc), ptStats, pupOvBytes, 1)
if pbi ne 0 then
   [
   let stats = lv pbi>>PBI.pup.words
   if pbi>>PBI.pup.type eq ptAck &
    stats>>Stats.version eq gcStatsVersion then
      [
      if gcu>>GCU.stats then Enqueue(oldStatsQ, gcu>>GCU.stats)
      let lenStatBlock = (pbi>>PBI.pup.length-pupOvBytes+1)/2
      gcu>>GCU.stats = Allocate(sysZone, lenStatBlock)
      MoveBlock(gcu>>GCU.stats, lv pbi>>PBI.pup.words, lenStatBlock)
      ]
   ReleasePBI(pbi)
   ]
] repeat

//----------------------------------------------------------------------------
and GateConVersion(stream) be
//----------------------------------------------------------------------------
[
let stats = gcu>>GCU.stats; if stats eq 0 return
PutTemplate(stream, "$S [$UO#$UO#]: $S", gcName, gcNet, gcHost,
 lv stats>>Stats.versionText)
if stats>>Stats.startTime↑0 ne 0 then
   [
   let interval = vec 1; ReadCalendar(interval)
   DoubleSubtract(interval, lv stats>>Stats.startTime)
   let secs = Divide32x16(interval, 60)
   let mins = Divide32x16(interval, 60)
   PutTemplate(stream, " up $D:$2F0D:$2F0D", interval!1, mins, secs)
   ]
]

//----------------------------------------------------------------------------
and GateConSummary(stream) be
//----------------------------------------------------------------------------
[
let stats = gcu>>GCU.stats; if stats eq 0 return
PutTemplate(stream, "Free PBIs: $D  ", stats>>Stats.freePBIs)
if stats>>Stats.freePages ne 0 then
   PutTemplate(stream, "Free Pages: $D  ", stats>>Stats.freePages)
]

//----------------------------------------------------------------------------
and RestartGateway() be GCSCommand("*NRestart Gateway", ptRestart)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and HaltGateway() be GCSCommand("*NHalt Gateway", ptHalt)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and GCSCommand(string, type) be
//----------------------------------------------------------------------------
[
unless Confirm(string) return
let soc = vec lenPupSoc; OpenLevel1Socket(soc)
let pbi = SendCommand(GetBuf(soc), type, pupOvBytes)
if pbi eq 0 % pbi>>PBI.pup.type ne ptAck then
   Ws("*NThe Gateway Control Server doesn't answer.")
if pbi then ReleasePBI(pbi)
CloseLevel1Socket(soc)
]