--** occam bindings for the Wiring API.
-- @module wiring

#IF NOT (DEFINED (WIRING.MODULE))
#DEFINE WIRING.MODULE

#INCLUDE "avr.module"

--{{{  constants
VAL INT LOW IS #0:
VAL INT HIGH IS #1:

VAL INT INPUT IS #0:
VAL INT OUTPUT IS #1:

VAL INT SERIAL  IS #0:
VAL INT DISPLAY IS #1:

VAL INT LSBFIRST IS 0:
VAL INT MSBFIRST IS 1:

VAL INT CHANGE IS 1:
VAL INT FALLING IS 2:
VAL INT RISING IS 3:

VAL INT INTERNAL IS 3:
VAL INT DEFAULT IS 1:
VAL INT EXTERNAL IS 0:


-- Mappings for pin.location
VAL []INT DDR.MAP IS
  [DDRD, DDRD, DDRD, DDRD, DDRD, DDRD, DDRD, DDRD,
   DDRB, DDRB, DDRB, DDRB, DDRB, DDRB,
   DDRC, DDRC, DDRC, DDRC, DDRC, DDRC]:
VAL []INT PORT.MAP IS
  [PORTD, PORTD, PORTD, PORTD, PORTD, PORTD, PORTD, PORTD,
   PORTB, PORTB, PORTB, PORTB, PORTB, PORTB,
   PORTC, PORTC, PORTC, PORTC, PORTC, PORTC]:
VAL []INT PIN.MAP IS
  [PIND, PIND, PIND, PIND, PIND, PIND, PIND, PIND,
   PINB, PINB, PINB, PINB, PINB, PINB,
   PINC, PINC, PINC, PINC, PINC, PINC]:
--}}}

--{{{  PROC delay
--* Wait for a period of time.
-- @param millis Time in wait, in milliseconds
PROC delay (VAL INT millis)
  TIMER tim:
  INT t:
  SEQ
    tim ? t
    tim ? AFTER t PLUS millis
:
--}}}

--{{{ PROC die
INLINE PROC die (VAL []BYTE error)
  SEQ
    --{{{  force error to be used
    INT n:
    n := SIZE error
    --}}}
    CAUSEERROR ()
:
--}}}

--{{{  FUNCTION pin.location
--* Map an Arduino pin number to a DDR register, PORT register, PIN register
-- and bit number.
--
-- On the Arduino NG, Diecimilia, Duemilanove and similar boards:
--
-- [@item] digital pins 0-7 map to [@ref PORTD] bits 0-7
-- [@item] digital pins 8-13 map to [@ref PORTB] bits 0-5
-- [@item] analog pins 0-5 are also known as digital pins 14-19, and map to
--   [@ref PORTC] bits 0-5
--
-- A request for a pin out of range will result in an unrecoverable error.
--
-- @param pin Arduino pin number, as marked on the board
-- @returns ddr.reg The [@text DDR] register
-- @returns port.reg The [@text PORT] register
-- @returns pin.reg The [@text PIN] register
-- @returns bit The bit number in all the above registers
INT, INT, INT, INT INLINE FUNCTION pin.location (VAL INT pin)
  INT bit:
  VALOF
    IF
      (pin < 0) OR (pin > 19)
        die ("requested pin number is not valid (must be between 0 and 19)")
      pin < 8
        bit := pin
      pin < 14
        bit := pin - 8
      TRUE
        bit := pin - 14
    RESULT DDR.MAP[pin], PORT.MAP[pin], PIN.MAP[pin], bit
:
--}}}

--{{{  PROC digitalWrite
PROC digitalWrite (VAL INT pin, state)
  INT r.ddr, r.port, r.pin, bit:
  PLACED [MAX.PORT]BYTE ports 0:
  #PRAGMA DEFINED ports
  SEQ
    r.ddr, r.port, r.pin, bit := pin.location (pin)
    ports[r.port] := (ports[r.port] /\ (~BV (bit))) \/ ((BYTE state) << bit)
:
--}}}
--{{{  PROC digitalRead
PROC digitalRead (VAL INT pin, RESULT INT state)
  INT r.ddr, r.port, r.pin, bit:
  PLACED [MAX.PORT]BYTE ports 0:
  #PRAGMA DEFINED ports
  SEQ
    r.ddr, r.port, r.pin, bit := pin.location (pin)
    state := (INT ((ports[r.pin] /\ (BV (bit))) >> bit))
:
--}}}

--{{{  PROC pinMode
PROC pinMode (VAL INT pin, mode)
  INT r.ddr, r.port, r.pin, bit:
  PLACED [MAX.PORT]BYTE ports 0:
  #PRAGMA DEFINED ports
  SEQ
    r.ddr, r.port, r.pin, bit := pin.location (pin)
    ports[r.ddr] := (ports[r.ddr] /\ (~BV (bit))) \/ ((BYTE mode) << bit)
:
--}}}

--{{{  PROC beginSerial
--* Initialise the serial port.
-- @param baud Baud rate
PROC beginSerial (VAL INT32 baud)
  VAL INT32 factor IS (((F.CPU / 16) + (baud / 2)) / baud) - 1:
  VAL [4]BYTE factor.bytes RETYPES factor:

  PLACED [MAX.PORT]BYTE ports 0:
  SEQ
    ports[UBRR0H] := factor.bytes[1]
    ports[UBRR0L] := factor.bytes[0]

    ports[UCSR0C] := 3 << UCSZ00
    ports[UCSR0B] := BV (TXEN0)
:
--}}}
--{{{  PROC serialWrite
--* Write a string to the serial port.
-- @param string Bytes to write
PROC serialWrite (VAL []BYTE string)
  SEQ i = 0 FOR SIZE string
    PLACED [MAX.PORT]BYTE ports 0:
    #PRAGMA DEFINED ports
    SEQ
      WHILE (ports[UCSR0A] /\ BV (UDRE0)) = 0
        SKIP
      ports[UDR0] := string[i]
:
--}}}
--{{{  PROC serialWriteInt
--* Write an [@code INT] to the serial port in hex.
PROC serialWriteInt (VAL INT n)
  VAL []BYTE digits IS "0123456789abcdef":
  SEQ i = 3 FOR 4 STEP -1
    serialWrite ([digits[(n >> (i * 4)) /\ #F]])
:
--}}}
--{{{  PROC serialWriteInt32
--* Write an [@code INT32] to the serial port in hex.
PROC serialWriteInt32 (VAL INT32 n)
  VAL []BYTE digits IS "0123456789abcdef":
  SEQ i = 7 FOR 8 STEP -1
    serialWrite ([digits[INT ((n >> (i * 4)) /\ #F)]])
:
--}}}

#ENDIF
