View Single Post
Old 04 October 2015, 20:10   #36
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
clock problem

Hi,

I’m the coder of Copper-rulez-AGAin.lha (Aminet).

daxb you are right. A demo that returns to the workbench shouldn’t affect the RTC. Well, I didn’t care about this fact and I was caught .

To all members of this discussion: It was a pleasure to read because of its high quality stuff. I’ve learned a lot.

Good work modrobert . Your sourcecode helped me to understand how to use the battery clock resource and the timer device. BTW, I’ve optimized and expanded your code a little bit:

Code:
move.l	$4.w,a6
move.l	a6,a5			; execbase in a5
lea     battresname(pc),a1      ; battclock.resource
jsr 	 -498(a6)		; OpenResource()
movea.l	d0,a4		        ; battclockbase in a4
move.l	a4,d0			; hmm...
beq.b  .fail
.battok	
moveq	#$28,d0		        ; want 40 bytes allocated (size of 						; timer-request-structure)
move.l	#$10001,d1		; MEMF_ANY, MEMF_CLEAR?
jsr	-198(a6)		; AllocMem()
move.l	d0,a3		        ; allocated mem in a3
tst.l	d0
beq	.fail
move.l	d0,a1
lea	timerdevname(pc),a0
moveq	#0,d0			; Unit 0 = UNIT_MICROHZ
moveq 	#0,d1			; No flags
jsr	-444(a6)		; OpenDevice()
tst.l	d0			; equal 0 ?
bne.b   .fail
moveq	#0,d0			; start building IORequest / 							; TimerRequest structure
move.b	d0,8(a3)		; LN_Type = NULL		
move.b	d0,9(a3)		; LN_Pri = NULL
move.l	d0,$a(a3)		; LN_Name = No pointer
move.l	d0,$e(a3)		; MN_ReplyPort = No pointer
movea.l	a4,a6			; battclockbase in a4
move.l 	d0,$24(a3)		; TV_micro =0 microseconds 
jsr	-12(a6)		        ; ReadBattClock()
movea.l	a3,a1
move.l	d0,$20(a3)		; TV_secs = unix time in seconds
beq.b	.no_sys_time_refresh    ; Equal 0 (Invalid value) ?
movea.l	a5,a6			; execbase in a5
move.w	#$b,$1c(a3)		; IO_Command = TR_SETSYSTIME
jsr	-456(a6)		; DoIO()
.no_sys_time_refresh
movea.l a3,a1
jsr	-450(a6)		; CloseDevice()
movea.l	a3,a1
moveq	#$28,d0		        ; free the 40 bytes
jmp	-210(a6)		; FreeMem()
.fail
rts

battresname     dc.b    'battclock.resource',0
timerdevname   dc.b    'timer.device',0

But the battery clock resource has a bug. Working with OS 3.0 on a real A1200 without a RTC the return value of OpenResource() is always nonzero. Apart from this behaviour OpenResource() returns a zero when working on a MiST. Thats's were my fixed demo aborted with the error message "Can't find battery backed up clock". The behaviour of this function call seems to be different on original hardware and on a MiST which doesn't have a RTC.

So it's better to use PHX's solution for refreshing the system time.
PHX, I've also checked your startup code using the TOD and expanded it. Good idea to use the TOD directly in addition to the system .
The TOD must not be set to zero and messed up this way. You can also get the difference from TOD before and after the demo/intro. But a TOD overflow must be checked. Because TOD runs independently from any interrupts they can be all turned off.

Code:
  
  move.l  $4.w,a6            ;Execbase
  lea     timer_request_struc(pc),a1 ;Timer-request-structure
  moveq   #0,d0              ;Unit 0 (UNIT_MICROHZ) & Null for entrys in struc
  move.b  d0,8(a1)           ;LN_Type: Entry type = Null
  move.b  d0,9(a1)           ;LN_Pri: Priority of the structure = Null
  moveq   #0,d1              ;No Flags for device
  move.l  d0,$a(a1)          ;LN_Name: No name for the structure
  lea     timer_device_name(pc),a0 ;Pointer to name of Timer-Device
  move.l  d0,$e(a1)          ;MN_ReplyPort: No Reply-Port
  jsr     -444(a6)           ;OpenDevice()
  tst.l   d0
  bne.s   open_timer_device_error
  lea     timer_request_struc(pc),a1
  move.w  #$a,$1c(a1)        ;IO_Command = TR_GETSYSTIME
  jsr     -456(a6)           ;DoIO()
  jsr     -120(a6)           ;Disable()

;Take over the machine...

  move.l  #$bfe001,a4        ;CIA-A base adress
  moveq   #0,d0
  move.b  $a00(a4),d0        ;TOD-clock bits 23-16
  swap    d0                 ;Shift bits to the right position
  move.b  $900(a4),d0        ;TOD-clock bits 15-8
  lsl.w   #8,d0              ;Shift bits to the right position
  move.b  $800(a4),d0        ;TOD-clock bits 7-0
  move.l  d0,TOD_time_save   ;Save time before demo/intro starts

  movem.l d0-d7/a0-a6,-(a7)
  bsr     demo               ;start demo/intro
  movem.l (a7)+,d0-d7/a0-a6

  move.l  TOD_time_save(pc),d0 ;Time before starting demo/intro
  moveq   #0,d1
  move.b  $a00(a4),d1        ;TOD-clock Bits 23-16
  swap    d1
  move.b  $900(a4),d1        ;TOD-clock Bits 15-8
  lsl.w   #8,d1
  move.b  $800(a4),d1        ;TOD-clock Bits 7-0
  cmp.l   d0,d1              ;TOD overflow?
  bge.s   no_TOD_overflow    ;No -> skip
  move.l  #$ffffff,d2        ;Max TOD value
  sub.l   d0,d2              ;Difference until overflow
  add.l   d2,d1              ;+ value after overflow
  bra.s   TOD_okay
  CNOP 0,4                   ;Longword alignment for 68020+
no_TOD_overflow
  sub.l   d0,d1              ;Get normal difference without overflow
TOD_okay
  move.l  d1,TOD_time_save   ;Save period of demo/intro

;Restore system...

  move.l  $4.w,a6            ;Execbase
  jsr     -126(a6)           ;Enable()
  move.l  TOD_time_save(pc),d0 ;Period of demo/intro
  moveq   #0,d1
  move.b  212(a6),d1         ;Get VBlankFrequency
  lea     timer_request_struc(pc),a1
  divu.w  d1,d0              ;Calculate seconds
  move.w  #$b,$1c(a1)        ;IO_command = TR_SETSYSTIME
  move.l  d0,d1              ;Save seconds in d1
  ext.l   d0                 ;Word to longword
  add.l   d0,$20(a1)         ;TV_SECS: Set Unix-Time seconds
  swap    d1                 ;Remainder of division
  mulu.w  #10000,d1          ;*10000 = µs
  add.l   d1,$24(a1)         ;TV_MICRO: Set Unix-Time microseconds
  jmp     -456(a6)           ;DoIO()
  CNOP 0,4
open_timer_device_error
  rts

  CNOP 0,4
TOD_time_save		DC.L 0

timer_request_struc	DS.B 40

timer_device_name	DC.B "timer.device",0
  EVEN
I fixed my demo with this way using the TOD clock. And now it works fine on a MiST. (Thanks to kolla for his support ). The fixed version of Copper-rulez-AGAin.lha is uploaded on Aminet.

Quote:
Very good. There is just one disadvantage: you need an RTC and at least OS2.0(?) for battclock.resource
PHX, I think I've got a solution for OS 1.x systems with a RTC. I found this little C sourcecode for calculating UNIX time for PCs:

Code:
/** Konvertiert gegliederte UTC-Angaben in Unix-Zeit.
 * Parameter und ihre Werte-Bereiche:
 * - jahr [1970..2038]
 * - monat [1..12]
 * - tag [1..31]
 * - stunde [0..23]
 * - minute [0..59]
 * - sekunde [0..59]
 */
long unixzeit(int jahr, int monat, int tag,
              int stunde, int minute, int sekunde)
{
  const short tage_seit_jahresanfang[12] = /* Tage seit Jahresanfang ohne Tage des aktuellen Monats und ohne Schalttag */
    {0,31,59,90,120,151,181,212,243,273,304,334};

  int schaltjahre = ((jahr-1)-1968)/4
                  - ((jahr-1)-1900)/100
                  + ((jahr-1)-1600)/400;

  long tage_seit_1970 = (jahr-1970)*365 + schaltjahre
                      + tage_seit_jahresanfang[monat-1] + tag-1;

  if ( (monat>2) && (jahr%4==0 && (jahr%100!=0 || jahr%400==0)) )
    tage_seit_1970 += 1; /* +Schalttag, wenn jahr Schaltjahr ist */

  return sekunde + 60 * ( minute + 60 * (stunde + 24*tage_seit_1970) );
}
The PC uses as a start date 01.01.1970 00:00:00 instead of 01.01.1978 00:00:00 like the amiga. Care must be taken when calculating the leap years. Use 1976 instead of 1968. The distance between the start year and the previous leap year should be 2 years or there will be a wrong UNIX time.

After analysing SetClock1.2 & 1.3 and ReadBattClock() in ROM I wrote this RTC-handler. It checks if a RTC is available, reads the RTC, converts the date/time to amiga UNIX time and sets the system time. As a bonus I've included an alternative subroutine to seek&reset the RTC.

More information about the OKI RTC can be found here:
http://www.amigawiki.de/lib/exe/fetch.php?media=dearts:m6242b_oki_datasheet.pdf
Attached Files
File Type: s RTC-Handler.s (11.6 KB, 143 views)
dissident is offline  
 
Page generated in 0.04640 seconds with 12 queries