home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / amigalib / d978 / mouseclock.lha / MouseClock / Source / SetMClock.asm next >
Encoding:
Assembly Source File  |  1994-04-04  |  23.1 KB  |  908 lines

  1. ***************************************************************************
  2. ;
  3. ; SetMClock v1.21  14-Sep-93  by Adriano De Minicis 
  4. ;
  5. ;--------------------------------------------------------------------------
  6. ; Assembler used: Devpac3
  7. ; Link: Blink SetMClock.o lib amiga.lib sc sd nd
  8. ;--------------------------------------------------------------------------
  9. ; HISTORY:
  10. ;
  11. ; V1.0  22-Jul-93  First release: ok, but OS1.2 can't see bool tooltypes
  12. ; V1.1  29-Jul-93  Changed configuration file name from "clock.config" to
  13. ;                  "MClock.upd", changed tooltypes (MODE=load|save|zero)
  14. ;                  to maintain compatibility with OS1.2
  15. ; V1.2  07-Aug-93  Fixed bug in WBParse with OS1.2
  16. ; V1.21 14-Sep-93  Fixed bug in updating "MClock.upd".
  17. ;                  Now performs a complete check to the configuration file.
  18. ;--------------------------------------------------------------------------
  19. ;
  20. ; NOTE: I've used a compact notation to show the content of a register
  21. ;       when it contains more than one variable:
  22. ;       
  23. ;       (x) means x is a byte,   [y] means y is a word
  24. ;       
  25. ;       Example: d0 = (day)(month)[year] means:
  26. ;                     byte #3 (upper) is day, byte #2 is month,
  27. ;                     lower word is year
  28. ;
  29. ***************************************************************************
  30.  
  31.         opt    l+        ; linkable
  32.  
  33.         include    exec/exec_lib.i
  34. ;        include dos/dos_lib.i
  35. ;        include    dos/dos.i
  36.         include devices/timer.i
  37.         include    graphics/text.i
  38.         include graphics/rastport.i
  39.         include    intuition/intuition.i
  40.         include    intuition/intuition_lib.i
  41.         include    workbench/workbench.i
  42.         include    workbench/icon_lib.i
  43.         include workbench/startup.i
  44.  
  45. ******  Startup code  *****************************************************
  46.             
  47.         include smallstartup.i
  48.  
  49. ******  Macro definitions  ************************************************
  50.  
  51. CALL        MACRO
  52.         jsr    _LVO\1(a6)
  53.         ENDM
  54.  
  55. ******  Constants and variables  ******************************************
  56.         
  57.         even
  58.  
  59. LIBVERS        equ    33        ; library version required (v1.2)
  60. ABSEXECBASE    equ    4
  61.  
  62. ARWIDTH        equ    450        ; requester width
  63. ARHEIGHT    equ    37        ; requester height
  64.  
  65. LOAD        equ    'LOAD'        ; used as a long value (4 chars)
  66. SAVE        equ    'SAVE'        ;             "
  67. ZERO        equ    'ZERO'        ;             "
  68.  
  69. SHORTTIME    equ    100        ; delay in microseconds
  70. LONGTIME    equ    1000        ; delay in microseconds
  71. STOPTIME    equ    5000        ; delay (µs) after bus stop                                      ; and 'load'
  72.  
  73. CLK_ADDR_RD    equ    %11010011    ; I2C address of clock (read)
  74. CLK_ADDR_WR    equ    %11010010    ; I2C address of clock (write)
  75.  
  76. MONTH_MASK    equ    %00011111    ; mask for month data (BCD)
  77. DAYHR_MASK    equ    %00111111    ; mask for day and hour
  78. MINSEC_MASK    equ    %01111111    ; mask for minutes and seconds
  79.  
  80. TimerPort    dc.l    0        ; TimerPort pointer
  81. TimeReq        dc.l    0        ; TimeRequest pointer
  82. TimerDevOpen    dc.w    0        ; true if timer device opened
  83.  
  84. _IntuitionBase    dc.l    0
  85. _IconBase    dc.l    0
  86.  
  87. *---- Days from the beginning of the year ----*
  88.  
  89. DayMonth    dc.w    0,31,59,90,120,151,181,212,243,273,304,334,365
  90. DayMonthLeap    dc.w    0,31,60,91,121,152,182,213,244,274,305,335,366
  91.  
  92. *---- Version string ----*
  93.  
  94. VersionString    dc.b    '$VER: SetMClock 1.21 (14.9.93)',0
  95.  
  96. *---- String definitions ----*
  97.  
  98. intui_name    INTNAME
  99. timer_name    TIMERNAME
  100. icon_name    ICONNAME
  101.  
  102. AROkTxt        dc.b    'OK',0            ; Negative text for req.
  103. ToolStr        dc.b    'MODE',0
  104. LoadStr        dc.b    'load',0
  105. SaveStr        dc.b    'save',0
  106. ZeroStr        dc.b    'zero',0
  107. HelpTxt        dc.b    'CLI Usage: SetMClock load|save|zero',$0a
  108.         dc.b    'WB Tooltypes:   MODE=load|save|zero',0
  109. ErrNoTimer    dc.b    'Can''t open timer.device',0
  110. ErrNoClock    dc.b    'Can''t find battery backed up clock',0
  111. ErrBadData    dc.b    'Bad data in S:MClock.upd',0
  112. ErrClkNotSet    dc.b    'Battery backed up clock not set',0
  113. ErrNoConfig    dc.b    'Can''t open S:MClock.upd',0
  114. ErrNoSave    dc.b    'Can''t save '
  115. ConfigFile    dc.b    'S:MClock.upd',0
  116.  
  117. ConfigModified    dc.b    0    ; true if config.file modified
  118.  
  119.         even
  120.         
  121. *---- Configuration file buffer ----*
  122.  
  123. ConfigBuffer    dc.b    0    ; day (1..31)
  124.         dc.b    0    ; month (1..12)
  125.         dc.w    0    ; year (1978..2066) (from Amiga0 to Amiga1E6)
  126.  
  127.         even
  128.         
  129. *---- Intuitexts for AutoRequest ----*
  130.  
  131. ARBodyIT    dc.b    0,1,RP_JAM2,0
  132.         dc.w    10,8
  133.         dc.l    0        ;default font
  134. ARBTxt        dc.l    0,0
  135.  
  136. ARNegIT        dc.b    0,1,RP_JAM2,0
  137.         dc.w    6,3
  138.         dc.l    0        ;default font
  139.         dc.l    AROkTxt, 0    
  140.  
  141. ******  External references for linker  ***********************************
  142.  
  143.         XREF    _CreatePort        ; amiga.lib
  144.         XREF    _DeletePort        ; amiga.lib
  145.         XREF    _CreateExtIO        ; amiga.lib
  146.         XREF    _DeleteExtIO        ; amiga.lib
  147.  
  148.         XDEF    _SysBase
  149.         XDEF    _DOSBase
  150.  
  151. ******  Main  *************************************************************
  152.  
  153.         even
  154.         
  155. main        lea    intui_name(pc),a1
  156.         moveq    #LIBVERS,d0
  157.         CALLEXEC OpenLibrary        ; open intuition.library
  158.         move.l    d0,_IntuitionBase
  159.         beq    Exit            ; exit immediately
  160.  
  161. GetTimer    moveq    #0,d0
  162.         move.l    d0,-(sp)
  163.         move.l    d0,-(sp)
  164.         jsr    _CreatePort        ; create Port for timer
  165.         addq    #8,sp
  166.         move.l    d0,TimerPort
  167.         beq.s    NoTimer
  168.         
  169.         moveq    #IOTV_SIZE,d1
  170.         move.l    d1,-(sp)
  171.         move.l    d0,-(sp)
  172.         jsr    _CreateExtIO        ; create ExtIO for timer
  173.         addq    #8,sp
  174.         move.l    d0,TimeReq
  175.         beq.s    NoTimer
  176.         
  177.         lea    timer_name(pc),a0
  178.         move.l    d0,a1
  179.         moveq    #UNIT_MICROHZ,d0
  180.         moveq    #0,d1
  181.         CALLEXEC OpenDevice        ; open timer.device (microHz)
  182.         tst.l    d0
  183.         beq.s    TimerOk
  184.  
  185. NoTimer        lea    ErrNoTimer(pc),a0
  186.         moveq    #RETURN_ERROR,d7
  187.         bra    ErrorExit
  188.  
  189. TimerOk        move    #-1,TimerDevOpen
  190.  
  191. ******  Parse arguments passed from CLI or WB  ****************************
  192.  
  193.         move.l    WBenchMsg(pc),d0
  194.         bne    WBParse
  195.  
  196. *---- Called from CLI ----*
  197.  
  198. CLIParse    move.l    CmdLinePtr(pc),a0    ; pointer to command line
  199.         move.b    (a0)+,d0        ; get first char
  200.         asl.w    #8,d0            
  201.         move.b    (a0)+,d0        ; get second char
  202.         swap    d0
  203.         move.b    (a0)+,d0        ; get third char
  204.         asl.w    #8,d0
  205.         move.b    (a0)+,d0        ; get fourth char
  206.         and.l    #$DFDFDFDF,d0        ; uppercase the four chars
  207.         
  208. select_choice    cmp.l    #LOAD,d0
  209.         beq    LoadClock
  210.         cmp.l    #SAVE,d0
  211.         beq    SaveClock
  212.         cmp.l    #ZERO,d0
  213.         beq    ZeroClock
  214.         
  215.         lea    HelpTxt(pc),a0        ; no match, show help
  216.         moveq    #0,d7            ; no error code
  217.         bra    ErrorExit
  218.  
  219. *---- Called from WB ----*
  220.  
  221. WBParse        move.l    #LOAD,d5        ; d5 = choice (default)
  222.  
  223.         move.l    d0,a0
  224.         move.l    sm_NumArgs(a0),d1    ; d1 = NumArgs
  225.         move.l    sm_ArgList(a0),a1    ; a1 = pointer to first WBArg
  226.  
  227.         cmp    #1,d1            ; only one arg?
  228.         bls.s    1$            ; yes, skip
  229.         addq    #wa_SIZEOF,a1        ; no, get the second
  230.         
  231. 1$        move.l    wa_Name(a1),d7        ; d7 = icon who called us
  232.         beq    11$
  233.         move.l    wa_Lock(a1),d1        ; file lock
  234.         beq    11$
  235.         CALLDOS    CurrentDir        ; change to the proper dir.
  236.         move.l    d0,d6            ; d6 = old lock
  237.         
  238.         lea    icon_name(pc),a1
  239.         moveq    #LIBVERS,d0
  240.         CALLEXEC OpenLibrary        ; open icon.library
  241.         move.l    d0,a6            ; save icon.lib pointer
  242.         tst.l    d0            ; check if open error
  243.         beq.s    10$
  244.  
  245.         move.l    d7,a0
  246.         CALL    GetDiskObject        ; open icon who called us
  247.         tst.l    d0
  248.         beq.s    9$
  249.         
  250.         move.l    d0,a5            ; save pointer to diskobj
  251.         move.l    do_ToolTypes(a5),a0    ; a0 = tooltype pointer
  252.  
  253.         lea    ToolStr(pc),a1
  254.         CALL    FindToolType        ; search 'MODE' tooltype
  255.         tst.l    d0
  256.         beq.s    5$            ; not found, use default
  257.  
  258.         move.l    d0,a4            ; save toolstring pointer
  259.         move.l    a4,a0
  260.         lea    ZeroStr(pc),a1
  261.         CALL    MatchToolValue        ; search 'zero' string
  262.         tst.l    d0
  263.         beq.s    4$            ; not found
  264.         move.l    #ZERO,d5        ; found: choice = ZERO
  265.  
  266. 4$        move.l    a4,a0
  267.         lea    SaveStr(pc),a1
  268.         CALL    MatchToolValue        ; search 'save' string
  269.         tst.l    d0
  270.         beq.s    5$            ; not found
  271.         move.l    #SAVE,d5        ; found: choice = SAVE
  272.  
  273. 5$        move.l    a5,a0
  274.         CALL    FreeDiskObject        ; free icon
  275.  
  276. 9$        move.l    a6,a1
  277.         CALLEXEC CloseLibrary        ; close icon.library
  278. 10$        move.l    d6,d0
  279.         beq.s    11$
  280.         CALLDOS    CurrentDir        ; restore old directory
  281. 11$        move.l    d5,d0
  282.         bra    select_choice
  283.         
  284.  
  285. ******  Close and exit  ***************************************************        
  286.  
  287. *---- Exits with error code in D7 and error string in A0 ----*
  288.  
  289. ErrorExit    bsr    puts
  290.         bra.s    close
  291.  
  292. *---- Normal exit code ----*
  293.  
  294. CloseExit    moveq    #0,d7            ; no error code
  295.  
  296. close        move    TimerDevOpen(pc),d0
  297.         beq.s    1$
  298.         move.l    TimeReq(pc),a1
  299.         CALLEXEC CloseDevice        ; close timer device
  300.  
  301. 1$        move.l    TimeReq(pc),d0
  302.         beq.s    2$
  303.         moveq    #IOTV_SIZE,d1
  304.         move.l    d1,-(sp)
  305.         move.l    d0,-(sp)
  306.         jsr    _DeleteExtIO        ; delete TimeReq
  307.         addq    #8,sp
  308.  
  309. 2$        move.l    TimerPort(pc),d0
  310.         beq.s    3$
  311.         move.l    d0,-(sp)
  312.         jsr    _DeletePort        ; delete TimerPort
  313.         addq    #4,sp
  314.         
  315. 3$        move.l    _IntuitionBase(pc),d0
  316.         beq.s    4$
  317.         move.l    d0,a1
  318.         CALLEXEC CloseLibrary        ; close intuition library
  319.  
  320. 4$        bra    Exit
  321.  
  322.  
  323. ******  Print string  *****************************************************   
  324. ;
  325. ; Prints null terminated string to standard output adding a line feed,
  326. ; if called from CLI, or shows a requester if started from WB.
  327. ;
  328. ; Input: A0 pointer to null terminated string
  329. ; Registers used: A0..A3, D0..D3
  330.  
  331. puts        tst.l    WBenchMsg        ; from CLI?
  332.         bne.s    autoreq            ; no
  333.  
  334.         move.l    OutputFH(pc),d1        ; d1 = output filehandle
  335.         beq.s    3$            ; handle=0 ?, skip
  336.  
  337.         moveq    #1,d3            ; d3 = text lenght
  338.         move.l    a0,d2            ; d2 = text pointer
  339. 1$        move.b    (a0)+,d0        ; current char = 0 ?
  340.         beq.s    2$            ; yes, end of text
  341.         addq    #1,d3            ; no, inc lenght
  342.         bra.s    1$            ;
  343. 2$        move.b    #$0a,-(a0)        ; add a line feed
  344.         move.l    a0,a3            ; save pointer to null char
  345.         CALLDOS    Write            ; print text
  346.         move.b    #0,(a3)            ; restore null terminator
  347.  
  348. 3$        rts
  349.  
  350. autoreq        move.l    a0,ARBTxt        ; set pointer to my text
  351.         moveq    #0,d0            ; no positive IDCMP flags
  352.         moveq    #0,d1            ; no negative IDCMP flags
  353.         move.l    #ARWIDTH,d2        ; width of autorequester
  354.         moveq    #ARHEIGHT,d3        ; heght of autorequester
  355.         move.l    d0,a0            ; no window
  356.         move.l    d0,a2            ; no positive text
  357.         lea    ARBodyIT(pc),a1        ; positive text
  358.         lea    ARNegIT(pc),a3        ; negative text
  359.         CALLINT AutoRequest
  360.         rts
  361.  
  362.  
  363. ******  Read/Write configuration file  ************************************
  364. ;
  365. ; Input: D4 = Mode: (0=Read, 1=Write)
  366. ;        D5 = ErrorCode
  367. ;        A5 = ErrorString
  368.  
  369. OpenConfig    lea    ConfigFile(pc),a0
  370.         move.l    a0,d1
  371.         move.l    #MODE_OLDFILE,d2    ; read mode (file must exist)
  372.         tst.l    d4            ; read or write ?
  373.         beq.s    1$            ; read, ok
  374.         move.l    #MODE_NEWFILE,d2    ; save mode (create new file)
  375. 1$        CALLDOS    Open            ; open config file
  376.         move.l    d0,d7            ; d7 = file handle
  377.         bne.s    OpenOk
  378.         
  379. RWError        move.l    a5,a0            ; error string
  380.         move.l    d5,d7
  381.         bra    ErrorExit
  382.  
  383. OpenOk        move.l    d0,d1
  384.         lea    ConfigBuffer(pc),a0
  385.         move.l    a0,d2
  386.         moveq    #4,d3
  387.         tst.b    d4            ; read or write ?
  388.         bne.s    1$
  389.         CALL    Read
  390.         bra.s    2$
  391. 1$        CALL    Write
  392. 2$        move.l    d0,d6
  393.         move.l    d7,d1
  394.         CALL    Close
  395.         cmp    #4,d6
  396.         bne.s    RWError
  397.         rts
  398.  
  399. ******  I2C ROUTINES  *****************************************************
  400.  
  401. *---- Hardware register for mouse port #2 ----*
  402.  
  403. CiaA_PortA    equ    $bfe001        ; bit 7 = fire, used for
  404.                     ; SCL line (I2C serial clock)
  405. CiaA_DDRA    equ    $bfe201        ; data direction (0=in, 1=out)
  406.                     ; for CiaA_PortA
  407. PotGo        equ    $dff034        ; bit 14 = PotY, bit 15 = OE
  408.                     ; used for data output (SDA)
  409. Joy1Dat        equ    $dff00c        ; bit 1 = /Right (SDA input)
  410.                     ; bit 9 = /Left (SCL input)
  411.  
  412. *---- Definitions ----*
  413.  
  414. I2CStatus    dc.b    0        ; Status of I2C: 0=ok
  415.                     ; bit 0=timeout, bit 1=no ack
  416.         even
  417.  
  418. POT0        equ    $8000        ; value of POTGO for SDA=0
  419. POT1        equ    $C000        ; value of POTGO for SDA=1
  420.  
  421. TIMEOUT        equ    10000        ; max timeout loops
  422.  
  423. FIRE        equr    a3
  424. POT        equr    a4
  425. JOY        equr    a5
  426.  
  427. ;-----  Start I2C communications  -----------------------------------------
  428. ;
  429. ; Call this routine to initialize registers and the I2C bus 
  430. ;
  431. ; IMPORTANT: registers A3,A4,A5 are used by I2C routines. Do NOT modify
  432. ;            them until StopI2C
  433. ;
  434. ; Register modified: D0..D1, A0..A1, A3..A6 
  435.  
  436. StartI2C    move.b    #0,I2CStatus    ; status ok
  437.         lea    CiaA_PortA,FIRE
  438.         lea    PotGo,POT
  439.         lea    Joy1Dat,JOY
  440.         bset.b    #7,(FIRE)    ; set SCL=1
  441.         bset.b    #7,CiaA_DDRA    ; set SCL as output
  442.         bsr    sda1
  443.         bsr    sda0
  444.         bsr    scl0
  445.         bra    shortdelay
  446.  
  447. ;-----  Stop I2C communication  -------------------------------------------
  448.  
  449. StopI2C        bsr    sda0
  450.         bsr    scl1
  451.         bsr    sda1
  452.         bclr.b    #7,CiaA_DDRA    ; set SCL as input
  453.         move    #0,(POT)    ; set SDA as input (superfluous ?)
  454.         move.l    #STOPTIME,d0    ; delay from stop condition
  455.         bra    delay
  456.  
  457. ;-----  Transmit byte in d2 converting to BCD  ----------------------------
  458. ; Input: D2 byte to transmit (binary)
  459. ; Register modified: D0..D3, A0..A1, A6
  460.  
  461. TXByteToBCD    moveq    #0,d0        ; clear result
  462.         move.b    d2,d0        ; d0 = b (byte binary)
  463.         moveq    #10,d1
  464.         divu    d1,d0        ; d0 = [b MOD 10][b DIV 10]
  465.         move    d0,d2        ; d2 = b DIV 10
  466.         lsl    #4,d2        ; d2 = (b DIV 10)*16
  467.         swap    d0
  468.         add    d0,d2        ; d2 = (b DIV 10)*16 + (b MOD 10)
  469.         bra.s    TXByte        ; transmit
  470.  
  471.  
  472. ;-----  Receive byte in d4, mask it, and convert from BCD -----------------
  473. ;
  474. ; Input:  D5 byte mask
  475. ; Output: D4 byte received (long)
  476. ; Register modified: D0..D4, A0..A1, A6
  477.  
  478. RXByteFromBCD    bsr.s    RXByte        ; d2 = B, byte received (BCD)
  479.         and.b    d5,d4        ; mask byte
  480.         move    d4,d0
  481.         and.b    #$0F,d0        ; d0 = LSD 
  482.         lsr    #4,d4        ; d4 = MSD
  483.         moveq    #10,d1
  484.         mulu    d1,d4        ; d4 = MSD*10
  485.         add    d0,d4        ; d4 = MSD*10+LSD
  486.         rts
  487.  
  488. ;-----  Transmit byte in d2 -----------------------------------------------
  489. ;
  490. ; Input: D2 byte to transmit
  491. ; Register modified: D0..D3, A0..A1, A6
  492.  
  493. TXByte        moveq    #7,d3        ; bit counter
  494. 1$        bsr.s    txbit        
  495.         lsl.b    #1,d2
  496.         dbra    d3,1$
  497.         bsr.s    rxbit        ; read ack bit
  498.         btst    #0,d2        ; test ack bit
  499.         beq.s    2$        ; ack=0, ok
  500.         bset.b    #1,I2CStatus    ; ack error
  501. 2$        rts
  502.  
  503. ;-----  Receive byte in d4  -----------------------------------------------
  504. ;
  505. ; Output: D4 byte received (long)
  506. ; Register modified: D0..D4, A0..A1, A6
  507.  
  508. RXByte        moveq    #7,d3        ; bit counter
  509.         moveq    #0,d4        ; byte to be read
  510. 1$        bsr.s    rxbit
  511.         lsl    #1,d4
  512.         or.b    d2,d4
  513.         dbra    d3,1$
  514.         moveq    #0,d2        ; transmit ack=0
  515.         bra.s    txbit
  516.  
  517. ******  I2C subroutines  **************************************************
  518.  
  519. ; Transmit bit 7 of register D2
  520.  
  521. txbit        btst    #7,d2        ; Transmit bit 7 of d2
  522.         bne.s    1$
  523.         bsr.s    sda0
  524.         bra.s    2$
  525. 1$        bsr.s    sda1
  526. 2$        bsr.s    scl1
  527.         bsr    shortdelay
  528.         bra.s    scl0
  529.  
  530. ; Returns bit received in bit 0 of D2
  531.  
  532. rxbit        move    #POT1,(POT)    ; set SDA=1 without feedback
  533.         bsr    longdelay    ; wait until SDA=1 (can't check)
  534.         bsr.s    scl1
  535.         bsr    shortdelay
  536.         move    (JOY),d2    ; read SDA (bit 1 negated)
  537.         lsr    #1,d2
  538.         not    d2
  539.         and    #1,d2
  540.         bra.s    scl0
  541.  
  542. sda0        move    #POT0,(POT)    ; set SDA=0
  543.         move    #TIMEOUT,d0
  544. 1$        move    (JOY),d1
  545.         btst    #1,d1
  546.         dbne    d0,1$
  547.         bra.s    TimeTest
  548.  
  549. sda1        move    #POT1,(POT)    ; set SDA=1
  550.         move    #TIMEOUT,d0
  551. 1$        move    (JOY),d1
  552.         btst    #1,d1
  553.         dbeq    d0,1$
  554. TimeTest    cmp    #-1,d0        ; if d0=-1 there is a timeout
  555.         bne.s    TimeOk
  556.         bset.b    #0,I2CStatus    ; timeout error
  557. TimeOk        rts
  558.  
  559. scl0        bclr.b    #7,(FIRE)    ; set SCL=0
  560.         move    #TIMEOUT,d0
  561. 1$        move    (JOY),d1
  562.         btst    #9,d1
  563.         dbne    d0,1$
  564.         bra.s    TimeTest
  565.  
  566. scl1        bset.b    #7,(FIRE)    ; set SCL=0
  567.         move    #TIMEOUT,d0
  568. 1$        move    (JOY),d1
  569.         btst    #9,d1
  570.         dbeq    d0,1$
  571.         bra.s    TimeTest
  572.  
  573. ******  Timer delays  *****************************************************
  574. ;
  575. ; Register modified: d0,d1,a0,a1
  576.  
  577. shortdelay    move.l    #SHORTTIME,d0        ; short delay entry point
  578.         bra.s    delay
  579. longdelay    move.l    #LONGTIME,d0        ; long delay entry point
  580. delay        move.l    TimeReq(pc),a1        ; delay in d0 (microsec)
  581.         moveq    #TR_ADDREQUEST,d1
  582.         move.w  d1,IO_COMMAND(a1)
  583.         moveq    #0,d1
  584.         move.l    d1,(IOTV_TIME+TV_SECS)(a1)
  585.         move.l    d0,(IOTV_TIME+TV_MICRO)(a1)
  586.         CALLEXEC DoIO
  587.         rts
  588.  
  589. ******  Save Clock  *******************************************************
  590. ;
  591.  
  592. ;-----  Get system time in d0  --------------------------------------------
  593.  
  594. SaveClock    move.l    TimeReq(pc),a1
  595.         moveq    #TR_GETSYSTIME,d1
  596.         move.w    d1,IO_COMMAND(a1)
  597.         CALLEXEC DoIO
  598.         move.l    TimeReq(pc),a1
  599.         move.l    (IOTV_TIME+TV_SECS)(a1),d0
  600.  
  601. ;-----  Convert system time to date  --------------------------------------
  602. ;
  603. ; Input:  d0 = system_time.seconds
  604. ; Output: d5 = [year][month]
  605. ;         d6 = [ hr ][ day ]
  606. ;         d7 = [ sec][ min ]
  607.  
  608. ConvFromSysTime    move.b    d0,d7        ; d0 = seconds from Jan,1 78
  609.         and    #3,d7        ; d7 = secs mod 4
  610.         lsr.l    #2,d0        ; d0 = secs/4
  611.         move    #21600,d1
  612.         divu    d1,d0        ; d0 = [secs/4][days]
  613.         
  614.         move.l    d0,d2
  615.         clr    d2
  616.         swap    d2        ; d2 = secs/4
  617.         moveq    #15,d1
  618.         divu    d1,d2
  619.         swap    d2        ; d2 = [mins][sec/4]
  620.         lsl    #2,d2        ; d2 = [mins][sec]
  621.         or    d2,d7        ; d7 = sec
  622.         swap    d7        ; d7 = [sec][0]
  623.         clr    d2
  624.         swap    d2        ; d2 = [0][mins]
  625.         moveq    #60,d1
  626.         divu    d1,d2        ; d2 = [min][hr]
  627.         move    d2,d6        ; d6 = hr
  628.         swap    d6        ; d6 = [hr][0]
  629.         swap    d2        ; d2 = [hr][min]
  630.         move    d2,d7        ; d7 = [sec][min] - OK
  631.         
  632.         move    #1978,d1    ; d0 = days, d1=year
  633. yloop        bsr    LeapCheck    ; d2 = # of days of d1
  634.         cmp    d2,d0        ; days < days year ?
  635.         bmi.s    yearfound
  636.         sub    d2,d0        ; no, subtract days of this year
  637.         addq    #1,d1        ; next year
  638.         bra.s    yloop
  639. yearfound    move    d1,d5
  640.         swap    d5        ; d5 = [year][?]
  641.         lea    (DayMonth+2)(pc),a0
  642.         cmp    #366,d2        ; leap year ?
  643.         bne.s    searchmonth
  644.         lea    (DayMonthLeap+2)(pc),a0
  645. searchmonth    move.w    #1,d5        ; d5 = [year][month]
  646.         addq    #1,d0        ; days starts from 1..
  647. mloop        cmp    (a0)+,d0    ; days <= DayMonth(month) ?
  648.         bls.s    monthfound
  649.         addi.w    #1,d5        ; inc month (warning: NO QUICK!)
  650.         bra.s    mloop
  651. monthfound    subq    #4,a0        ; a0 points to month-1
  652.         sub    (a0),d0        ; d0 = day
  653.         move    d0,d6        ; d6 = [hr][day]
  654.  
  655. ;-----  Set configuration date  -------------------------------------------
  656.  
  657.         move.b    d6,d0        ; d0 = (day)
  658.         lsl    #8,d0        ; d0 = (day)(0)
  659.         or.b    d5,d0        ; d0 = (day)(month)
  660.         swap    d0
  661.         move.l    d5,d1
  662.         swap    d1        ; d1 = [month][year]
  663.         move    d1,d0        ; d0 = (day)(month)[year]
  664.         move.l    d0,ConfigBuffer ; save to buffer
  665.  
  666. ;-----  Save date/time to battery clock  ----------------------------------
  667.  
  668.         bsr    StartI2C    ; initialize I2C bus
  669.         move.b    #CLK_ADDR_WR,d2 ; write mode
  670.         bsr    TXByte        ; transmit address
  671.         move.b    I2CStatus(pc),d0
  672.         bne    I2CErrorStop    ; bus error - Stops
  673.         move.b    d5,d2
  674.         bsr    TXByteToBCD    ; transmit month
  675.         move.b    d6,d2
  676.         bsr    TXByteToBCD    ; transmit day
  677.         swap    d6
  678.         move.b    d6,d2
  679.         bsr    TXByteToBCD    ; transmit hour
  680.         move.b    d7,d2
  681.         bsr    TXByteToBCD    ; transmit min
  682.         bsr    StopI2C
  683.  
  684.         move.b    I2CStatus(pc),d0
  685.         bne    I2CError    ; error
  686.  
  687. ;-----  Save configuration date  ------------------------------------------
  688.  
  689.         moveq    #1,d4            ; save mode
  690.         moveq    #RETURN_FAIL,d5        ; error code
  691.         lea    ErrNoSave(pc),a5    ; error string
  692.         bsr    OpenConfig        ; save
  693.         bra    CloseExit
  694.         
  695.  
  696. ******  Load Clock  *******************************************************
  697. ;
  698. ;
  699. ;-----  Load date/time from battery clock  --------------------------------
  700.  
  701. LoadClock    bsr    StartI2C    ; initialize I2C bus
  702.         move.b    #CLK_ADDR_RD,d2    ; read mode
  703.         bsr    TXByte        ; transmit address
  704.         move.b    I2CStatus(pc),d0
  705.         bne.s    I2CErrorStop    ; bus error - Stops
  706.         moveq    #MONTH_MASK,d5    ; month mask
  707.         bsr    RXByteFromBCD    ; receive month
  708.         move    d4,-(sp)    ; save month
  709.         moveq    #DAYHR_MASK,d5    ; day & hour mask
  710.         bsr    RXByteFromBCD    ; recieve day
  711.         move    d4,d6
  712.         swap    d6
  713.         bsr    RXByteFromBCD    ; receive hour
  714.         move    d4,d6        ; d6 = [day][hr]
  715.         tst.l    d6
  716.         bne.s    ClockSet    ; ok, clock is set
  717. ClockNotSet    bsr    StopI2C        ; clock is not set (day=0 & hr=0)
  718.         moveq    #RETURN_FAIL,d7
  719.         lea    ErrClkNotSet(pc),a0
  720.         bra    ErrorExit                        
  721. ClockSet    moveq    #MINSEC_MASK,d5    ; min & sec mask
  722.         bsr    RXByteFromBCD    ; receive min
  723.         move    d4,d7
  724.         swap    d7
  725.         bsr    RXByteFromBCD    ; receive sec
  726.         move    d4,d7        ; d7 = [min][sec]
  727.         move    (sp)+,d5    ; d5 = [?][month]
  728.         bsr    StopI2C        ; end of I2C communication
  729.         
  730.         move.b    I2CStatus(pc),d0
  731.         beq.s    RConfig            ; status ok
  732.         bne.s    I2CError
  733.  
  734. ;-----  I2C error condition  ----------------------------------------------
  735.  
  736. I2CErrorStop    bsr    StopI2C            ; stop I2C and exit
  737. I2CError    moveq    #RETURN_ERROR,d7    ; error code
  738.         lea    ErrNoClock(pc),a0    ; error string
  739.         bra    ErrorExit
  740.  
  741. ;-----  Read configuration file  ------------------------------------------
  742.  
  743. RConfig        movem.l    d5-d7,-(sp)        ; save clock data
  744.         moveq    #0,d4            ; read mode
  745.         moveq    #RETURN_FAIL,d5        ; error code
  746.         lea    ErrNoConfig(pc),a5    ; error string
  747.         bsr    OpenConfig        ; read config
  748.         movem.l    (sp)+,d5-d7        ; restore registers
  749.  
  750.         move.l    ConfigBuffer(pc),d4    ; d4 = config data (cxxx)
  751.         
  752. ;-----  Test configuration range  -----------------------------------------
  753.  
  754.         move.l    d4,d3            ; d3 = (cday)(cmonth)[cyear]
  755.         cmp    #1978,d3        ; cyear < 1978 ?
  756.         bpl    ChkUpYBound        ; no
  757.  
  758. ConfigError    moveq    #RETURN_FAIL,d7        ; error code
  759.         lea    ErrBadData(pc),a0    ; error string
  760.         bra    ErrorExit
  761.         
  762. ChkUpYBound    cmp    #2067,d3        ; cyear >= 2067 ?
  763.         bpl    ConfigError        ; yes, error
  764.  
  765.         swap    d3            ; d3 = (cday)(cmonth)
  766.         tst.b    d3            ; cmonth = 0 ?
  767.         beq.s    ConfigError
  768.         cmp.b    #12,d3            ; cmonth > 12 ?
  769.         bhi.s    ConfigError
  770.         lsr    #8,d3            ; d3 = (cday)
  771.         beq.s    ConfigError        ; cday = 0 ?
  772.         cmp.b    #31,d3            ; cday > 31 ?
  773.         bhi.s    ConfigError
  774.             
  775.         
  776. ;-----  Check if configuration file must be updated  ----------------------
  777.  
  778.         move    d4,d3            ; d3 = cyear
  779.         swap    d4            ; d4 = (cday)(cmonth)
  780.         cmp.b    d4,d5            ; month > cmonth ?
  781.         bhi.s    CheckZero        ; yes, ok
  782.         bne.s    UpdateYear        ; month < cmonth, update year
  783.         lsr    #8,d4            ; d4 = cday
  784.         move.l    d6,d0
  785.         swap    d0            ; d0 = [hr][day]
  786.         cmp.b    d4,d0            ; day < cday ?
  787.         bmi.s    UpdateYear        ; yes, update year
  788.  
  789. CheckZero    move.b    ConfigModified(pc),d0    ; Forced update ? (ZeroClok)
  790.         bne.s    Update            ; yes, update
  791.         bra.s    SetYear            ; no, skip
  792.  
  793. UpdateYear    addq    #1,d3            ; inc year
  794. Update        move.l    d6,d2
  795.         swap    d2            ; d2 = [hr][day]
  796.         lsl    #8,d2            ; d2 = (day)(0)
  797.         move.b    d5,d2            ; d2 = (day)(month)
  798.         swap    d2
  799.         move    d3,d2            ; d2 = current date (config)
  800.         move.l    d2,ConfigBuffer        ; save into config buffer
  801.         move.b    #$FF,ConfigModified    ; set modified flag
  802.  
  803. SetYear        swap    d5
  804.         move    d3,d5
  805.         swap    d5            ; d5 = [year][month]
  806.  
  807. ;-----  Convert to system time format  ------------------------------------
  808. ;
  809. ; Input: d5 = [year][month]
  810. ;        d6 = [ day][ hr  ]
  811. ;        d7 = [ min][ sec ]
  812.  
  813.                  
  814. ConvToSysTime    moveq    #0,d0        ; clear d0
  815.         move    d7,d0        ; d0 = [0,sec]
  816.         swap    d7        ; d7 = [sec,min]
  817.         move    d6,d2        ; d2 = hr
  818.         moveq    #60,d1
  819.         mulu    d1,d2        ; d2 = hr*60
  820.         add    d7,d2        ; d2 = hr*60+min
  821.         mulu    d1,d2        ; d2 = hr*3600+min*60
  822.         add.l    d2,d0        ; d0 = seconds from midnight
  823.         
  824.         clr    d6        ; d6 = [day,0]
  825.         swap    d6        ; d6 = day (long)
  826.         subq    #1,d6        ; days start from 0..
  827.         lea    (DayMonth-2)(pc),a0    ; array base pointer
  828.         move    d5,d1        ; d1 = month
  829.         lsl    #1,d1
  830.         add    (a0,d1.w),d6    ; d6 = days from Jan,1 (long)
  831.         move    d5,d3        ; d3 = month
  832.         swap    d5        ; d5 = [month,year]
  833.         move    d5,d1        ; d1 = year
  834.         sub    #1978,d5    ; d5 = year-1978
  835.         move    #365,d2
  836.         mulu    d5,d2        ; d2 = (year-1978)*365
  837.         add    d2,d6        ; d6 = days from Jan,1 1978 (no leap)
  838.         bsr    LeapCheck    ; d2 = # of days of current year
  839.         cmp    #365,d2
  840.         beq.s    1$        ; normal year
  841.         cmp    #2,d3        ; leap year: is month > feb ?
  842.         bls.s    1$
  843.         addq    #1,d6        ; yes, add one day for current year
  844. 1$        cmp    #2000,d1    ; year > 2000 ?
  845.         bls.s    2$        ; no
  846.         subq    #1,d6        ; yes, sub. one day (2000 isn't leap)
  847. 2$        sub    #1977,d1    ; compute (year-1977)/4,
  848.         lsr    #2,d1        ; number of leap years from 1978
  849.         add    d1,d6        ; d6 = # of days from Jan,1 78 - OK
  850.         move    #21600,d2
  851.         mulu    d2,d6
  852.         lsl.l    #2,d6        ; d6 converted in secs (*86400)
  853.         add.l    d6,d0        ; d0 = # of secs from Jan,1 78 - OK
  854.  
  855. ;-----  Set system time  --------------------------------------------------
  856.  
  857. SetSystemTime    move.l    TimeReq(pc),a1
  858.         moveq    #TR_SETSYSTIME,d1
  859.         move.w    d1,IO_COMMAND(a1)
  860.         move.l    d0,(IOTV_TIME+TV_SECS)(a1)
  861.         moveq    #0,d1
  862.         move.l    d1,(IOTV_TIME+TV_MICRO)(a1)
  863.         CALLEXEC DoIO
  864.  
  865. ;-----  Check if configuration file must be saved  ------------------------
  866.  
  867.         move.b    ConfigModified(pc),d0
  868.         beq.s    LBye            ; not modified, exits
  869.         moveq    #1,d4            ; mode = save
  870.         moveq    #RETURN_WARN,d5        ; error code
  871.         lea    ErrNoSave(pc),a5    ; error string
  872.         bsr    OpenConfig        ; save data
  873. LBye        bra    CloseExit        ; exits        
  874.         
  875.  
  876. ******  Zero clock  *******************************************************
  877.  
  878. ZeroClock    bsr    StartI2C    ; initialize I2C bus
  879.         move.b    #CLK_ADDR_WR,d2    ; write mode
  880.         bsr    TXByte        ; transmit address
  881.         bsr    StopI2C
  882.  
  883.         move.b    I2CStatus(pc),d0
  884.         bne    I2CError        ; error
  885.         
  886.         move.b    #$FF,ConfigModified    ; force update
  887.         bra    LoadClock
  888.  
  889.  
  890. ******  Leap check  *******************************************************
  891. ;
  892. ; Input : D1 year
  893. ; Output: D2 number of days of year D1
  894. ; Registers modified: D2
  895.  
  896. LeapCheck    move.l    d1,-(sp)    ; save d1
  897.         move    #365,d2
  898.         cmp    #2000,d1
  899.         beq.s    1$        ; year 2000 is not leap
  900.         and    #3,d1        ; check if year divisible by 4
  901.         bne.s    1$
  902.         addq    #1,d2        ; yes, it's a leap year: 366 days
  903. 1$        move.l    (sp)+,d1    ; restore d1
  904.         rts
  905.  
  906.         end
  907.