//-------------------------------------------------------------------
// Dallas DS1305 Serial Alarm Real-time Clock
// ds1305.xje Revision: 1.16
// XJEase device file
// (c)2004-2007 XJTAG Limited
//
// Disclaimer: XJTAG makes no guarantees whatsoever
// about this code.  You use it at your own risk ...
// This code requires XJTAG version 1.3.1 or later.
//
// This file tests Non-JTAG Real Time Clock using Test()(INT result)
//-------------------------------------------------------------------

DEVICE NAME := "DS1305-RTC"
  PINS
    SCLK  := 14;
    SDIN  := 15;
    SDOUT := 16;
    CE    := 12;
    nINT0 := 7;
    nINT1 := 9;
    OSC   := 5, 3;
  END;

  DISABLE DEVICE
    CE    := 0;
    nINT0 := Z;
    nINT1 := Z;
  END;

  TEST COVERAGE
    SCLK  := OPEN HI LO;
    SDIN  := OPEN HI LO;
    SDOUT := OPEN HI LO;
    CE    := OPEN HI LO;
    nINT0 := OPEN HI LO;
    OSC   := FUNCTIONAL;
  END;
END;

//---------------------------------------------------------------
// Constants
//---------------------------------------------------------------

CONST INT SECONDS          := 0x0;
CONST INT MINUTES          := 0x1;
CONST INT ALARM0_SEC       := 0x07;
CONST INT CONTROL_REGISTER := 0x0F;
CONST INT DEBUG            := FALSE;

//---------------------------------------------------------------
Test()(INT result)
//---------------------------------------------------------------

  INT read, i, timeout;
  INT minutes, seconds, currentSec;

  result := 1;

  PRINT("Testing Real-Time Clock ", DEVICE_REF, "\n");

  // Stop the clock and clear any IRQs.
  // Also, disable the write protect.
  WriteCycle(CONTROL_REGISTER, 0x80);
  ReadCycle(CONTROL_REGISTER)(read);

  IF read != 0x80 THEN
    PRINT("Failed to access RTC chip.\n");
    RETURN;
  END;

  // Now try reading without CE to check that it isn't shorted high.
  WriteSerial(CONTROL_REGISTER)();
  ReadSerial()(read);

  IF read = 0x80 THEN
    PRINT("Failed NOT to access RTC chip: CE shorted high.\n");
    RETURN;
  END;

  // Check the interrupt line.
  SET read := nINT0;
  IF read = 0 THEN
    PRINT("RTC interrupt request line 0 failed to go high.\n");
    RETURN;
  END;

  // Set alarm register to generate an IRQ every second.
  FOR i := ALARM0_SEC FOR 4
    WriteCycle(i, 0x80);
  END;

  // Clear the write protect bit and start the oscillator.
  WriteCycle(CONTROL_REGISTER, 0x1);

  ReadCycle(SECONDS)(currentSec);
  timeout := NOW() + 2000;

  IF DEBUG THEN
    ReadCycle(SECONDS)(seconds);
    ReadCycle(MINUTES)(minutes);
    PRINT("Time is ", HEX(minutes), "m ", HEX(seconds), "s\n");
  END;

  // Check that the oscillator has actually started.
  IF DEBUG THEN
    PRINT("currentSec = ", HEX(currentSec), "\n");
  END;

  DO
    ReadCycle(SECONDS)(seconds);
  WHILE seconds = currentSec && NOW() < timeout
  END;

  IF DEBUG THEN
    PRINT("After check time = ", HEX(seconds), "\n");
  END;

  IF seconds = currentSec THEN
    PRINT("RTC oscillator did not start.\n");
    RETURN;
  END;

  SET read := nINT0;
  IF read = 1 THEN
    PRINT("RTC Interupt request line 0 failed to go low.");
    RETURN;
  END;

  // Disable alarms.
  WriteCycle(CONTROL_REGISTER, 0x0);

  // Finally, clear the RTC memory so that the battery capacity
  // and any other remembered values are zeroed.
  FOR i := 0x20 TO 0x7F
    WriteCycle(i, 0);
    FLUSH;
  END;

  result := 0;
END;

//---------------------------------------------------------------
WriteCycle(INT address, INT data)()
//---------------------------------------------------------------
  address[7] := 1;
  SET SCLK :=1;
  SET CE := 1;
  WriteSerial(address)();
  WriteSerial(data)();
  SET CE := 0;
END;

//---------------------------------------------------------------
ReadCycle(INT address)(INT data)
//---------------------------------------------------------------
  address[7] := 0;
  SET SCLK :=1;
  SET CE := 1;
  WriteSerial(address)();
  ReadSerial()(data);
  SET CE := 0;
END;

//---------------------------------------------------------------
// Write 8 bits to the controller, MSB first.
WriteSerial(INT value)()
//---------------------------------------------------------------
  INT i;

  FOR i := 0 FOR 8
    SET SCLK := 0, SDIN := value [7 - i];
    SET SCLK := 1;
  END;
END;

//---------------------------------------------------------------
// Read 8 bits from the device, MSB first.
ReadSerial()(INT value)
//---------------------------------------------------------------
  INT i;
  value := 0;

  FOR i := 0 FOR 8
    value := value << 1;
    SET SCLK := 0;
    SET SCLK := 1, value[0] := SDOUT;
  END;
END;