--** @module player

#INCLUDE "occplayer.module"
#INCLUDE "useful.module"

#INCLUDE "player.inc"
#USE "debug"

VAL INT MAX.LASER.VALUE IS 800:
VAL INT MAX.SONAR.VALUE IS 500:
--DATA TYPE LASER IS [180]INT:
--DATA TYPE SONAR IS [16]INT:

VAL INT sonar.front IS 0:
VAL INT sonar.back IS 1:
VAL INT sonar.left IS 2:
VAL INT sonar.right IS 3:


-- Performs some basic sanity checking, so we 
-- don't do anything too stupid with the arrays.
BOOL FUNCTION check(VAL []INT data, VAL INT start, end)
  BOOL result:
  VALOF
    IF 
      end < start
        SEQ
          trace.sn ("End larger than start.")
          CAUSEERROR ()
      (end - start) > (SIZE data)
        SEQ
          trace.sn ("(End - Start) > size of array.")
          CAUSEERROR ()
      TRUE
        SKIP
    RESULT result
:

-- Averages in the slice requested
INT FUNCTION average (VAL []INT data, VAL INT start, length)
  INT total:
  VALOF
    INITIAL INT data.size IS (SIZE data):
    SEQ
      -- No longer checking anything, because we're 
      -- operating modulo the size of the array;
      -- we can't read past the array bounds.
      total := 0
      SEQ i = start FOR length
        total := total + data[(i \ data.size)]
    RESULT total / length
:

-- Finds the minimum value in the slice requested;
-- must be initialized with an initial minimum value.
INT FUNCTION min (VAL INT init, VAL []INT data, VAL INT start, length)
  INT min:
  VALOF
    INITIAL INT data.size IS (SIZE data):
    SEQ
      min := init
      SEQ i = start FOR length
        IF 
          min > data[(i \ data.size)]
            min := data[(i \ data.size)]
          TRUE
            SKIP
    RESULT min
:

-- Finds the maximum in the slice requested; needs an
-- initial value to compare against.
INT FUNCTION max (VAL INT init, VAL []INT data, VAL INT start, length)
  INT max:
  VALOF
    INITIAL INT data.size IS (SIZE data):
    SEQ
      max := init
      SEQ i = start FOR length
        IF 
          max < data[(i \ data.size)]
            max := data[(i \ data.size)]
          TRUE
            SKIP
    RESULT max
:

-- LASER PROCESSES
PROC laser.min.slice(CHAN LASER in?, CHAN INT out!, VAL INT start, length)
  WHILE TRUE
    LASER data:
    SEQ
      in ? data
      []INT data RETYPES data:
      out ! min(MAX.LASER.VALUE, data, start, length)
:

PROC laser.min(CHAN LASER in?, CHAN INT out!)
  laser.min.slice(in?, out!, 0, 180)
:

PROC laser.max.slice(CHAN LASER in?, CHAN INT out!, VAL INT start, length)
  WHILE TRUE
    LASER data:
    SEQ
      in ? data
      []INT data RETYPES data:
      out ! max(-1,  data, start, length)
:

PROC laser.max(CHAN LASER in?, CHAN INT out!)
  laser.max.slice(in?, out!, 0, 180)
:

PROC laser.average.slice(CHAN LASER in?, CHAN INT out!, VAL INT start, length)
  WHILE TRUE
    LASER data:
    SEQ
      in ? data
      []INT data RETYPES data:
      out ! average(data, start, length)
:

PROC laser.average(CHAN LASER in?, CHAN INT out!)
  laser.average.slice(in?, out!, 0, 180)
:

PROC laser.delta(CHAN LASER in?, out.1!, out.2!)
  WHILE TRUE
    LASER data:
    SEQ
      in ? data
      PAR
        out.1 ! data
        out.2 ! data
:

PROC laser.black.hole(CHAN LASER in?)
  WHILE TRUE
    LASER tmp:
    in ? tmp
:

-- SONAR PROCESSES

-- Sonar is different than the laser in that
-- you must provide an indicator for the side of the
-- robot you want values for.
PROC sonar.min(CHAN SONAR in?, VAL INT side, CHAN INT out!)
  WHILE TRUE
    SONAR data:
    SEQ
      in ? data
      CASE side
        sonar.front
          SEQ
            []INT data RETYPES data:
            --Range is [start,end); that is,
            -- inclusive on the start, not the end
            out ! min(MAX.SONAR.VALUE, data, 1, 6)
        sonar.back
          SEQ
            []INT data RETYPES data:
            out ! min(MAX.SONAR.VALUE, data, 9, 6)
        sonar.right
          SEQ
            []INT data RETYPES data:
            out ! min(MAX.SONAR.VALUE, data, 7, 2)
        sonar.left
          SEQ
            []INT data RETYPES data:
            out ! min(MAX.SONAR.VALUE, data, 15, 2)

:

PROC sonar.max(CHAN SONAR in?, VAL INT side, CHAN INT out!)
  WHILE TRUE
    SONAR data:
    SEQ
      in ? data
      CASE side
        sonar.front
          SEQ
            []INT data RETYPES data:
            out ! max(-1, data, 0, 6)
        sonar.back
          SEQ
            []INT data RETYPES data:
            out ! max(-1, data, 9, 6)
        sonar.right
          SEQ
            []INT data RETYPES data:
            out ! max(-1, data, 7, 2)
        sonar.left
          SEQ
            []INT data RETYPES data:
            out ! max(-1, data, 15, 2)
:

PROC sonar.average(CHAN SONAR in?, VAL INT side, CHAN INT out!)
  WHILE TRUE
    SONAR data:
    SEQ
      in ? data
      CASE side
        sonar.front
          SEQ
            []INT data RETYPES data:
            out ! average(data, 0, 6)
        sonar.back
          SEQ
            []INT data RETYPES data:
            out ! average(data, 9, 6)
        sonar.right
          SEQ
            []INT data RETYPES data:
            out ! average(data, 7, 2)
        sonar.left
          SEQ
            []INT data RETYPES data:
            out ! average(data, 15, 2)
:

PROC sonar.delta(CHAN SONAR in?, out.1!, out.2!)
  WHILE TRUE
    SONAR data:
    SEQ
      in ? data
      PAR
        out.1 ! data
        out.2 ! data
:

PROC sonar.black.hole(CHAN SONAR in?)
  WHILE TRUE
    SONAR tmp:
    in ? tmp
:
