gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Getting the time(SOLVED)

#156956 - yellowstar - Fri May 16, 2008 8:59 pm

How do I get the current time? This is for writing libpcap(.cap)
files on a DS.

That Wiki says to use time() for ts_sec. How do I use time()? I only got compile errors when I tried using it... Examples? That ts_usec field is microseconds, 1000 max. How do I get that?

This is for the program I wrote for capturing packets on an actual DS.(Needs tested.)


Last edited by yellowstar on Fri Jun 06, 2008 12:25 am; edited 3 times in total

#156957 - Maxxie - Fri May 16, 2008 9:14 pm

Since you need to work on the arm7 anyways, how about just reading out the wifi timer? http://nocash.emubase.de/gbatek.htm#dswifitimers

#156991 - yellowstar - Sat May 17, 2008 4:55 pm

I'd rather not deal with wifi timers - might screw other wifi stuff.(If my homebrew card was working I'd might try it...)

Anyway, I wrote code for these microsecond timings:
Code:

TIMER0_DATA = 0xFFFF - 32768;
TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1024;
...
r.tv_usec = (TIMER0_DATA / 33);//Gives, at max, 992.9696969696969696969696969697.(Microseconds hopefully)


Am I correct in assuming this code will give me the microseconds? Or should I use something else?(Code for precise, max 1000 microseconds, is welcome)

Now, how do I use time(), or how to get the seconds as stated in that Wiki...

#156996 - Maxxie - Sat May 17, 2008 5:34 pm

It will count up every 1024 / Busclock cycles

1024 / 33.513982 MHz = 0.00003055441... sec
Using every 33 (by your dividing) of them will give you a timer that is (roughly) precise by a
millisecond (0,0010082955... sec)

You aim to cound MICROseconds, which are a 1/1000 times milliseconds.

Reading out the usec counter on the wifi hardware doesn't influence anything else on the wifi hardware.

#157002 - yellowstar - Sat May 17, 2008 7:00 pm

So I could just use the below and it would use microseconds?
Code:

r.tv_usec = ((TIMER0_DATA / 33)*1000);
//Or should I multiply by 10?


I'd rather not tinker with those wifi timers - that would require more testing time, which other people would be doing...

#157003 - tepples - Sat May 17, 2008 7:07 pm

As I understand it, there are three clock generators in the DS: one each on the system bus, the wireless chipset, and the RTC. The system bus clock rate is thought to differ slightly between units.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#157010 - Maxxie - Sat May 17, 2008 7:53 pm

yellowstar wrote:
So I could just use the below and it would use microseconds?
Code:

r.tv_usec = ((TIMER0_DATA / 33)*1000);
//Or should I multiply by 10?


No, and no.

Multiplying that data transforms it but doesn't change what they express. You'll just transform a millisec precise millisec counter into a millisec precise microsec counter.

You need to change how that data is generated. I.e. with using no divider between the timer and the clock (TIMER_DIV_1) if you divide this by 33 you'll have _roughly_ usecs in the range from 0 to 1985. Half this range by substracting 993 if it is >= 993 (in exchange for a % 1000 to filter the range), then you have a _nearing_ to usecs that should be acceptable for the purpose of adding a time to your pcap

#157012 - yellowstar - Sat May 17, 2008 7:59 pm

I thought the 1 divider was too big for the 16-bit TIMER_DATA registers? What happens when the timer data hits the max value allowed for 16-bit values?

Obviously I don't have much experience with these timers... :-)

#157018 - Maxxie - Sat May 17, 2008 8:25 pm

Once the timer fires, it resets to it's reload value.
The reload value is the value written into TIMER_DATA(n) before changing the TIMER_ENABLE bit in TIMER_CR(n) from 0 to 1.

#157075 - yellowstar - Mon May 19, 2008 12:14 am

I changed my code to what you said, Maxxie. I discovered that there's a field in that libnds IPC struct, called unixTime. That's exactly what I need for tv_sec! (I'm aware of what will happen to that struct in the future... I'll need to update my code when that happens)

Once the program gets tested, with positive results for this, I'll stamp the usual SOLVED thing in the topic subject.

#157094 - wintermute - Mon May 19, 2008 6:05 am

man time wrote:

SYNOPSIS
#include <time.h>

time_t time(time_t *t);

DESCRIPTION
time() returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.

If t is non-NULL, the return value is also stored in the memory pointed to by t.

RETURN VALUE
On success, the value of time in seconds since the Epoch is returned. On error, ((time_t)-1) is returned, and errno is set appropriately.


Do not use internal libnds structures.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#157097 - HyperHacker - Mon May 19, 2008 6:21 am

tepples wrote:
As I understand it, there are three clock generators in the DS: one each on the system bus, the wireless chipset, and the RTC. The system bus clock rate is thought to differ slightly between units.
I imagine they all do, it'd be difficult to guarantee that level of precision.
_________________
I'm a PSP hacker now, but I still <3 DS.

#157158 - yellowstar - Mon May 19, 2008 9:28 pm

I guess I was using time() incorrectly. I had dka compile the following. I guess it's correct? It's what my version of DSCaptureTest is now using.(Similar to it)(Didn't upload this version yet)
Code:

long Time;
Time = time(NULL);


wintermute wrote:

Do not use internal libnds structures.

Um, I use such structures all the time whenever I write code to get the time of day, the date, and such. What am I supposed to use?(I guess it might have to do with time_t)

#157160 - Lazy1 - Mon May 19, 2008 9:36 pm

yellowstar wrote:

Um, I use such structures all the time whenever I write code to get the time of day, the date, and such. What am I supposed to use?(I guess it might have to do with time_t)


http://linux.die.net/man/3/localtime

#157828 - yellowstar - Fri May 30, 2008 3:22 am

Time doesn't work for me. All I get is zero all the time. The microsecond code seems to work...
Code:

void GetTime(pcapDumpPacketHeader *pkthdr)
{

pkthdr->tv_sec = (long)time(NULL);
pkthdr->tv_usec = (TIMER0_DATA / 33);
}

#157920 - yellowstar - Sun Jun 01, 2008 11:25 pm

I found the problem. It's not my code, it's dswifi's fault. My code in this dswifi program always returns zero, while the exact same code in a separate program works.

I'm writing my own code to calculate unix time.(Via that libnds IPC struct. I don't have any other option)
At the moment it's way off.

#157922 - yellowstar - Sun Jun 01, 2008 11:51 pm

DSwifi is major bugged. Those time fields in the IPC struct, all of them are ZERO! No wonder time fails, and my code fails!

#157924 - tepples - Mon Jun 02, 2008 12:59 am

yellowstar wrote:
IPC struct

This struct is an internal libnds structure that will change out from under your feet in new versions. Wintermute has recommended using public accessor methods from libc or libnds instead, such as time().
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#157925 - yellowstar - Mon Jun 02, 2008 1:06 am

I already said time doesn't work. It's probably because those time fields in the IPC struct are zero. And those are probably zero because dswifi shared-memory IPC data starts at the wrong spot, at the start of the IPC struct, instead of after it.

#157927 - tepples - Mon Jun 02, 2008 1:40 am

Have you tried getting the time with time() before turning on the radio, then just counting vblanks afterward?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#157928 - yellowstar - Mon Jun 02, 2008 1:44 am

Yes, and that failed. I tried doing that soon after the start of main, and nothing.

#157931 - yellowstar - Mon Jun 02, 2008 3:46 am

I tried disabling the Wifi init code on Arm7, and no Wifi function calls at all on Arm9, and nothing. I even tried the console init code from the template, and still nothing.

Arm7(Piratically the same code as template, minus those commented lines)
Code:

//---------------------------------------------------------------------------------
int main(int argc, char ** argv) {
//---------------------------------------------------------------------------------
   //REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR;


   // Reset the clock if needed
   rtcReset();

   //enable sound
   powerON(POWER_SOUND);
   SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F);
   IPC->soundData = 0;

   irqInit();

   //commandControl->shutdown=0;

   irqSet(IRQ_VBLANK, VblankHandler);

   //irqSet(IRQ_WIFI, Wifi_Interrupt);

   SetYtrigger(80);
   irqSet(IRQ_VCOUNT, VcountHandler);


   //irqSet(IRQ_FIFO_NOT_EMPTY,arm7_fifo);

   //REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_RECV_IRQ;

   //irqEnable(IRQ_FIFO_NOT_EMPTY | IRQ_VBLANK | IRQ_WIFI | IRQ_VCOUNT);

   //Wifi_SetSyncHandler(arm7_synctoarm9);

   IPC->mailBusy = 0;

   // Keep the ARM7 out of main RAM
   while (1) swiWaitForVBlank();
}


Arm9
Code:

//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
   //int sekrit_counter;

   powerON(POWER_ALL_2D | POWER_SWAP_LCDS);
   psych_mode=0;
   //*((volatile u16 *)0x0400010E) = 0;
   irqInit();
   irqEnable(IRQ_VBLANK);
   //*((volatile u16 *)0x0400010C) = -6553; // 6553.1 * 256 cycles = ~50ms;
   //*((volatile u16 *)0x0400010E) = 0x00C2; // enable, irq, 1/256 clock
   
   videoSetMode(0);   //not using the main screen
   videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);   //sub bg 0 will be used to print text
   vramSetBankC(VRAM_C_SUB_BG);

   SUB_BG0_CR = BG_MAP_BASE(31);

   BG_PALETTE_SUB[255] = RGB15(31,31,31);   //by default font will be rendered with color 255

   //consoleInit() is a lot more flexible but this gets you up and running quick
   consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);

char buf[256];
   while(1) {
       //Wifi_Update();
      WaitVbl();
      ClsBtm();
      
      time_t unixTime = time(NULL);
      
      sprintf(buf,"time_t %d",(int)unixTime);
      printf("%s\n",buf);//Always displays zero
      }

}

#157933 - yellowstar - Mon Jun 02, 2008 4:08 am

I used the iDeas debugger to check the IPC struct memory, and according to iDeas, it's completely empty...

#157934 - Cydrak - Mon Jun 02, 2008 4:18 am

yellowstar wrote:
Arm7(Piratically the same code as template, minus those commented lines) ...

How recently have you checked? The newer templates have added code over time (here's what I see in the template--top of main()):
Code:
readUserSettings();

powerON(POWER_SOUND);
writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP );
SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F);

irqInit();
initClockIRQ();    // !!

SetYtrigger(80);
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);    // !

Looks like initClockIRQ() sets up the clock, and installs a handler for IRQ_NETWORK (the clock interrupt) which updates IPC->unixTime (and thus hopefully time()) once a second. Mayhap that's what you're looking for..

Note: These seconds wouldn't be in sync with any variables or timers you may have--to get a proper tv_usec, you'll have to handle that yourself (probably by waiting for IRQ_NETWORK on the ARM7, then starting the counter or timer in question).

#157974 - yellowstar - Mon Jun 02, 2008 6:57 pm

So it's probably just that the arm7 used in wifi_lib_test is out of date, and that's what my code is using. Guess it's time to update to devkitARM 23 and latest libnds.

#157989 - yellowstar - Mon Jun 02, 2008 9:29 pm

I updated, but it still didn't work after I added the new code. The new code didn't have that IRQ_NETWORK, so I tried adding that, and it still wouldn't work.

#158001 - Cydrak - Tue Jun 03, 2008 1:22 am

I just updated to r23; time() works great with the default ARM7 code. (Mind, it'd worked for me before, too.)

So, I'm not sure what's up. "It still wouldn't work" doesn't tell me anything; is IPC->unixTime updating, or does it have a nonzero value at all? Check if irqInit() comes before initClockIRQ()... also, be sure you haven't accidentially disabled the interrupt. (Such as with code that writes REG_IE without preserving the old bits somewhere.)

Also if you're somehow testing on NO$GBA 2.6, it doesn't seem to handle these interrupts; the time seems correct (as of startup) but never updates.

#158004 - yellowstar - Tue Jun 03, 2008 3:27 am

My bad, I forgot to move the call to time() back to where it should be. Now it kind of works. Now the time is correct at first, but it never updates. Yes, I am testing on no$gba, as it's my only option. I tried other emulators, but it still doesn't work. And by the way, the IRQ_NETWORK code isn't needed, as I removed that and the program's behavior didn't change.

Even the Watch example for getting the time has this bug. And I remember when I first downloaded devkitPro and tried out that Watch example, the time never updated on that either. Does anybody know if that bug in that example has been fixed?

#158006 - wintermute - Tue Jun 03, 2008 4:19 am

It's not a bug, no$gba 2.6 doesn't emulate the RTC interrupt. Removing the IRQ_NETWORK code will make it fail on hardware.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#158007 - Cydrak - Tue Jun 03, 2008 4:29 am

yellowstar wrote:
Yes, I am testing on no$gba, as it's my only option. I tried other emulators, but it still doesn't work. And by the way, the IRQ_NETWORK code isn't needed, as I removed that and the program's behavior didn't change.

(Ed: wintermute beat me to it.)

I know hardware costs money, but if you're serious about development you need to test on it eventually--emulation only goes so far.

yellowstar wrote:
Even the Watch example for getting the time has this bug.

See above. I tried Watch and it's fine for me! I'm sure the authors put a lot of time and work into these tools and libraries; it'd be nice if you didn't keep attributing the bugs to them without actually testing. Failing on emulators is no surprise if the emulator doesn't support it, and I can think of several such things...

#158008 - yellowstar - Tue Jun 03, 2008 4:38 am

Then no emulator I tried emulates the RTC interrupt. I tried putting IRQ_NETWORK back, and the emulators still didn't work right.

wintermute wrote:

Removing the IRQ_NETWORK code will make it fail on hardware.

I checked the libnds source code from CVS, and I noticed initClockIRQ doesn't enable IRQ_NETWORK. This wasn't intentional, was it?
Interesting... I never knew,(at least I don't remember)
that in the BIOS there's a function for CRC16 calculation. What is that used for in official code? Is it faster than doing it manually?

#158027 - silent_code - Tue Jun 03, 2008 7:27 pm

i think it's used for what it was designed for, right? ;^p
i don't know much about rsa encryption, but it popped to mind. :^)

btw: i also haven't got to make rtc work in emulators, but typically it's working on hw. :^)
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#158031 - yellowstar - Tue Jun 03, 2008 7:43 pm

silent_code wrote:

i don't know much about rsa encryption, but it popped to mind. :^)

I'm positive that's not used. The only thing used in RSA is SHA-1, no CRC. I guess the BIOS CRC16 function is probably used for checking the checksums in the header when booting from slot-1.

Is it possible for the CRC16 generated from my manual CRC16 calculation code, to be different from the BIOS CRC16? I'm guessing header checksums should be fine, but what about checksums in the packets?(Such as beacon checksums)

#158065 - yellowstar - Wed Jun 04, 2008 3:11 am

I have switched the usec timer over to the Arm7, and the when the Arm9 needs the usec for the packets, it asks the Arm7 for it over FIFO and shared memory.

However, how do I get the timer going only when IRQ_NETWORK was triggered?

#158073 - Cydrak - Wed Jun 04, 2008 5:41 am

yellowstar wrote:
I have switched the usec timer over to the Arm7, and the when the Arm9 needs the usec for the packets, it asks the Arm7 for it over FIFO and shared memory.

Code takes time to run, doesn't it? What happens if the seconds are about to change?

yellowstar wrote:
However, how do I get the timer going only when IRQ_NETWORK was triggered?

There's a BIOS call to wait on IRQs--feel free to look it up.

However, come to think, I wouldn't use both timer and RTC for the same timestamp, lest they wander out of sync. I'd just check time() once, and start counting sec/usec from there, using some other method. This should work in NO$GBA, too (though as for the wifi, I rather doubt it).

#158086 - yellowstar - Wed Jun 04, 2008 5:09 pm

Cydrak wrote:
yellowstar wrote:
I have switched the usec timer over to the Arm7, and the when the Arm9 needs the usec for the packets, it asks the Arm7 for it over FIFO and shared memory.

Code takes time to run, doesn't it? What happens if the seconds are about to change?

Now my code only uses FIFO.

Cydrak wrote:

However, come to think, I wouldn't use both timer and RTC for the same timestamp, lest they wander out of sync. I'd just check time() once, and start counting sec/usec from there, using some other method. This should work in NO$GBA, too (though as for the wifi, I rather doubt it).

I left my code the way it is, starting the timer right after calling initClockIRQ. No, Wifi doesn't work on nocash. Doesn't crash it or anything, it just never finds any packets.

Quote:

I know hardware costs money, but if you're serious about development you need to test on it eventually--emulation only goes so far.

If I had a new homebrew card, I'd test on hardware all the time, but since I don't, emulators are my only option.

Quote:

See above. I tried Watch and it's fine for me! I'm sure the authors put a lot of time and work into these tools and libraries; it'd be nice if you didn't keep attributing the bugs to them without actually testing. Failing on emulators is no surprise if the emulator doesn't support it, and I can think of several such things...

Sorry, see above. Would be great if you would tell what things emulators don't support,(Of course I know about libfat issues)
since I have to test on emulators all the time.(In particular, no$gba)

#158094 - Cydrak - Wed Jun 04, 2008 8:43 pm

Quote:
If I had a new homebrew card, I'd test on hardware all the time, but since I don't, emulators are my only option.

Unfortunately, not a practical one. They are okay to start with, they can be great for debugging--but they also cause trouble, and you have to be ready for that.

Quote:
Would be great if you would tell what things emulators don't support

For the free NO$GBA 2.6 (feel free to correct, this is just from memory):
- Missing RTC interrupts
- Max 32KB of SRAM - not a bug, but my SC has 64KB
- Memory intensive code seems considerably slower - missing cache maybe?
- Exceptions seem not to work - eg. NULL pointer access
- VRAM banking differs slightly from real hardware
- Certain graphical features may crash if enabled before VRAM assigned
- Affine settings are ignored for 16-bit bitmap sprites
- Display capture may write garbage if the results aren't displayed - as in render to texture
- Possible to get FIFO "stuck" returning infinite stream of 0's (don't ask me, I don't know either!)

Btw, please don't take this to mean NO$GBA is a horrible program. In fact the combination of accuracy and speed is quite impressive. It just won't make toast, wash the car, or do your homework for you. ;p

(Ed: This is just going to get longwinded and offtopic... I should start a blog or something. XP)

#158102 - silent_code - Wed Jun 04, 2008 10:51 pm

<OT>
i found that no$gba 2.6 doesn't support 512x256 pixel bgs...
display capture doesn't work at all (at least the result isn't displayed).

today i found out, that although the rtc irq isn't supported, you still get the correct time at the beginning of the (rom) program. :^) that's an improvement over older (recent) versions, where time was always 0:0:0.
</OT>
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#158111 - yellowstar - Thu Jun 05, 2008 3:34 am

Cydrak wrote:


Btw, please don't take this to mean NO$GBA is a horrible program. In fact the combination of accuracy and speed is quite impressive. It just won't make toast, wash the car, or do your homework for you. ;p

(Ed: This is just going to get longwinded and offtopic... I should start a blog or something. XP)

I use nocash all the time - I hardly ever use the other emulators. In piratically every circumstance, nocash out did the other emulators almost every time in my testing. I don't mind this topic getting off topic at the moment, as I'm waiting for the weekend so me and Filb can start chatting, and so he can test DSCaptureTest. If the timing is correct, I'll stamp the usual SOLVED note on the topic title. By the way, how does one use libfat with nocash?

Quote:

- Exceptions seem not to work - eg. NULL pointer access
- VRAM banking differs slightly from real hardware
- Certain graphical features may crash if enabled before VRAM assigned

Once I intentionally tried the third one, and nocash had a problem with that. How exactly does VRAM banking differ? That first one sounds really bad. I haven't run into that one with nocash yet, from what I remember.

#158120 - Cydrak - Thu Jun 05, 2008 5:49 am

silent_code wrote:
display capture doesn't work at all (at least the result isn't displayed)

Hmm. Well, rendering can go to the display, capture or both. I've not looked in depth, but the first and last cases seemed OK to me. What barfs is when I display something else while capturing. (I do this on a screen that has hw-rendered thumbnails of my gamesaves.)

silent_code wrote:
today i found out, that although the rtc irq isn't supported, you still get the correct time at the beginning of the (rom) program. :^)

Yep, same here.

yellowstar wrote:
That first one sounds really bad. I haven't run into that one with nocash yet, from what I remember.

The reason you won't have "run into it" is that the exception is there to tell you about the problem. Its absence may allow bad pointers to go unnoticed, instead of crashing (or crashing sooner). Mind, the protection in a real DS is still limited, but it will catch the most blatant pointers.

yellowstar wrote:
How exactly does VRAM banking differ?

Honestly it's not much to worry about, I *think* all the common stuff is supported. If you care about this you have a fairly unusual setup, prolly because you saw the relevant board posts, or you were toying with real hardware..