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