![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
[SOLVED] PIC24EP512 wake-up on serial data problem |
Posted: Fri Aug 16, 2019 8:36 am |
|
|
Device: PIC24EP51GP806
Compiler: IDE: 5.071, PCD: 5.026
Hi guys,
I am having an issue with the receive channel of the UART on my MCU after waking-up from sleep. I will try to make it simple.
UART is tied to a modem. Commands are sent from MCU to modem and modem responds. All is fine here. e.g. MCU sends <AT> and modem responds <OK>.
After 1 minute without activity, MCU puts modem to sleep, sets a bunch of registers and enables interrupts that can wake-it up then it goes to sleep.
MCU can be woken-up on different types of external interrupts from different sensors but one of the wake-up methods is via the serial port if the modem sends it data... and this is where I have a problem which I can't figure-out:
First, the shutdown/wake-up code is always the same: I have a <Shutdown> command and ends with <sleep( SLEEP_FULL );>. At this point, the entire unit is asleep (MCU and modem). When any of the external interrupts trigger, the MCU is woken-up and executes whatever code it has after the sleep() command (code at wake-up). It's always the same code, regardless of what woke-it up, since that's the only place it sleeps and wakes-up. Then, in the case where the cause of the wake-up is through the serial port, there are two possible scenarios:
SCENARIO 1: A **CALL** comes-in. Although asleep (soft sleep), the incoming call makes the modem send a few serial messages (readable) to the MCU such as <RING> and a few others and when this happens, the UART RX interrupt on the MCU wakes-it up from sleep, then the MCU re-initializes a few things internally, then it intializes a few things on the modem by sending it a few AT commands and when all is done, the MCU (via the modem) sends me a text to say it is woken-up. This works fine 100% of the time.
SCENARIO 2: I send an **SMS** to the modem. In this case, the modem sends only one serial message to the MCU (+CMT: "number","date/time" etc) in which case the MCU wakes-up from sleep and carries-on with the same initialization procedure as scenario 1 above. But when it reaches the section to partially re-initialize a few things on the modem, immediately after its first AT command, to which the modem responds, the MCU's UART RD1 receive interrupt does not respond because I see the 'OK' response from the modem and that's it, nothing else happens. But in reality, if all was working fine, that 'OK' response should trigger another initialization command to the modem but that's not the case. The MCU does not handle the OK response therefore it's because the UART is not firing. In the case of the incoming call in scenario 1, the UART is working just fine.
The only difference between both is that in the case of an incoming call, the modem fires 3 serial messages to the MCU versus one message when a text comes-in. In either case, I don't really care what the messages are because it's only to wake-up the unit.
So obviously, the #INT_RDA interrupt is not working as expected because the MCU just sits there doing nothing...
Below is the sleep / wake-up sequence:
// Put modem to sleep
output_high( MODEM_PIN_DTR_SLEEP );
delay_ms( 500 );
// Disable all interrupts that will not be used for the wake-up process.
disable_interrupts( INT_UART1E );
disable_interrupts( INT_TBE );
disable_interrupts( INT_TIMER1 );
disable_interrupts( INT_DMA0 );
disable_interrupts( INT_RDA2 );
disable_interrupts( INTR_CN_PIN | CODEC_PIN_WCLK );
// Clear any pending interrupt flag
clear_interrupt( INT_UART1E );
clear_interrupt( INT_TBE );
clear_interrupt( INT_RDA2 );
clear_interrupt( INT_RDA );
clear_interrupt( INT_DMA0 );
clear_interrupt( INT_TIMER1 );
//*****************************************
// Enable interrupts that will wake-up unit
//*****************************************
enable_interrupts( INTR_CN_PIN | PIN_ATOD_MAIN );
enable_interrupts( INTR_CN_PIN | PIN_UART1_RX ); // Set RX pin as an external interrupt
enable_interrupts( INT_RDA ); // Enable serial receive interrupt
enable_interrupts( INT_EXT0 );
enable_interrupts( INT_EXT1 );
enable_interrupts( INT_EXT2 );
enable_interrupts( INT_EXT3 );
enable_interrupts( INT_EXT4 );
// Clear CN interrupt flag due to possible bug in compiler
#BIT CNIF=getenv("BIT:CNIF")
CNIF = FALSE;
clear_interrupt( INT_EXT0 );
clear_interrupt( INT_EXT1 );
clear_interrupt( INT_EXT2 );
clear_interrupt( INT_EXT3 );
clear_interrupt( INT_EXT4 );
// Stop the watchdog timer
setup_wdt( WDT_OFF );
// Disable all peripherral power
#byte PMD1 = getenv("byte:PMD1")
#byte PMD2 = getenv("byte:PMD2")
#byte PMD3 = getenv("byte:PMD3")
#byte PMD4 = getenv("byte:PMD4")
#byte PMD5 = getenv("byte:PMD5")
#byte PMD6 = getenv("byte:PMD6")
#byte PMD7 = getenv("byte:PMD7")
PMD1 = 0xFF;
PMD2 = 0xFF;
PMD3 = 0xFF;
PMD4 = 0xFF;
PMD5 = 0xFF;
PMD6 = 0xFF;
PMD7 = 0xFF;
#byte NVMCON=getenv("SFR:NVMCON");
#bit NVMSIDL=NVMCON.12;
NVMSIDL=TRUE;
#byte RCON = getenv("SFR:RCON")
#bit VREGS = RCON.8
#bit VREGSF = RCON.11
VREGS = FALSE;
VREGSF = FALSE;
#byte OSCCON = getenv("SFR:OSCCON");
#bit LPOSCEN = OSCCON.1;
LPOSCEN = FALSE;
// Sleep NOW
sleep( SLEEP_FULL );
*** UNIT NOW SLEEPING ***
// One of the external interrupts has been triggered, wake-up happens:
delay_cycles(100);
// Clear RAM, don't set any variables above this line
#zero_ram
// Take modem out of sleep mode
output_low( MODEM_PIN_DTR_SLEEP );
// Check which interrupt triggered the wake-up
unsigned long InterruptState = ( interrupt_active( INT_RDA ) << 6 ) |
( interrupt_active( INT_EXT0 ) << 5 ) |
( interrupt_active( INT_EXT1 ) << 4 ) |
( interrupt_active( INT_EXT2 ) << 3 ) |
( interrupt_active( INT_EXT3 ) << 2 ) |
( interrupt_active( INT_EXT4 ) << 1 );
enable_interrupts( INT_DMA0 );
enable_interrupts( INT_RDA );
enable_interrupts( INT_UART1E );
enable_interrupts( INT_TIMER1 );
enable_interrupts( INT_TBE );
enable_interrupts( INT_RDA2 );
clear_interrupt( INT_DMA0 );
clear_interrupt( INT_RDA );
clear_interrupt( INT_UART1E );
clear_interrupt( INT_TBE );
clear_interrupt( INT_TIMER1 );
clear_interrupt( INTR_CN_PIN );
clear_interrupt( INT_RDA2 );
enable_interrupts( GLOBAL );
Device_FinishInitialization();
***** FROM THIS POINT-ON *****
If MCU is woken-up by incoming call via a few modem messages, all works fine and MCU responds to incoming modem messages.
If MCU is woken-up by one incoming SMS via one modem message (+CMT), MCU sends-out a modem message, modem responds but MCU does not react to that response.
I'm sure it's something silly I missed but if I ask here, it's because my mind is boggled!
Thanks!
Ben
Last edited by benoitstjean on Tue Aug 20, 2019 8:21 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Fri Aug 16, 2019 9:19 am |
|
|
Without diving in too deeply, it sounds like a wake up time issue. Depending on the particular type of sleep you specify, the processor's clock can take a long time to stabilize and that can lead to the processor missing or mangling received characters.
Specifically how your receive data routine handles mangled messages is probably part of the issue. What you think the processor is receiving may not be what it is actually receiving.
If you have spare pins, create a soft uart and hook up a serial cable to it. Add code to record all received serial characters and dump them to the soft uart for the troublesome case you've been experiencing. You can then see exactly what the processor is receiving and come up with an alternative which is bulletproof.
The fix might be as easy as "if wake up not caused by call, poll modem to pull queued text messages". |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Fri Aug 16, 2019 9:40 am |
|
|
Hi newguy (who's been around since 2004!!),
Thanks for the reply. I can't change the circuit, it's on a 6-layer PCB with all pins soldered and doing something.
Since my post, I've been doing trial and error tests and finally got back to being able to properly wake-up the device but now it's doing something else which might be a bit easier to figure-out.
But for the test you suggest, honestly I really don't care what the incoming message is and garbled data is expected. The wake-up will occur on an incoming character therefore as soon as the first character is received, the unit wakes-up and that's what I want - I need to know what is the cause of the wake-up, that's it, I don't care if it was woken-up with "hello" or "potatoe".
This said, the sleep and wake-up method are always the same regardless of the interrupt. The fact that I also don't care about the incoming message waking-up the unit should not make any difference.
This is what is happening, when a call comes-in (these are sent from the modem to the MCU over the UART):
+CNSMOD: 8
+CNSMOD: 7
RING
The first two are just the modem saying that the service type has changed to LTE then HSPA. Then the modem sends "RING". But these arrive quite fast so the wake-up has already started.
In the case of an SMS, let's say I send "hello" to wake-up the unit, I get this:
+CMT: "6135551212","","19/08/16,11:06:00-16","hello"
In either scenarios, the only difference is the incoming call has 3 messages, the incoming SMS has one message, but both scenarios restart the device exactly the same way from the same location since they both triggered the RDA pin.
Just before going to sleep, I make the RDA pin an external CN interrupt to ensure that when it changes state on incoming data, it triggers the MCU.
Anyhow, I know it has to do with the UART RX interrupt, not sure whether it is related to the enable_interrupts( INTR_CNI | PIN_UART1_RX) or enable_interrupts( INT_RDA ) but definitely it is related to one of the two. I've been shuffling code around at the wake-up point and now I can wake-up the unit via an SMS but when I call interrupt_active( INT_RDA ) and read the input( INT_RDA ) pin state, both now return 0 as opposed to when it was not working, interrupt_active( INT_RDA ) would return 1.
I will continue to search.
Many thanks!
Ben |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Fri Aug 16, 2019 9:47 am |
|
|
Weird.... seems to somehow be related to enable_interrupts( GLOBAL ); because I brought this line immediately after the unit wakes-up and that's what now lets me wake-up the MCU via an SMS.
If I bring it back down further after I read all interrupt_active( xxx ), that's when I now get the state of the RDA interrupt pin but MCU locks-there as it seems the interrupt is not active.... |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Fri Aug 16, 2019 10:36 am |
|
|
Can you immediately kill CN interrupt/setup after waking?
Edit: do you have #errors added to your #use rs232 setup? I wonder if the UART overflowed and locked and that's what you're seeing? |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Fri Aug 16, 2019 3:20 pm |
|
|
Yes, I use #errors in #use rs232. Without that, the UART locks-up randomly once in a while.
So it seems I isolated the behaviour of the RDA/UART1_RX CN interrupts and it seems to depend on where I put <enable_interrupts( GLOBAL )> at MCU wake-up but definitely it should work and it's not so I will have to look into this monday morning.
I doesn't make any sense that incoming calls, which generates UART data, works fine and triggers the correct interrupts but an incoming SMS, which also generates data, does not.
I'm home now and I'll be looking at this monday morning.
Thanks again!
Ben |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Aug 19, 2019 7:24 am |
|
|
Back at this problem this morning.... I'll try to re-explain in a simpler way...
UART 1 RX pin is F2.
I need the entire system to wake-up (MCU and modem) on various external interrupts such as external sensors (this works) but also if the modem receives an SMS or incoming call.
Even when the modem is sleeping, a call placed to it will make the modem send "RING" over its UART to the MCU and if an SMS comes-in, it will make it send <+CMT: "nubmer","","date/time","message">, hence waking-up the entire system (MCU and modem) upon texting or calling the modem.
Just before making the MCU go to sleep (at which point the modem is sleeping), all the interrupts that should wake-up the MCU are enabled, then the MCU goes to sleep.
One important thing: When the unit is woken-up by SMS, I don't care what the SMS is... all I want is for the system to wake-up.
So my question: For the wake-up via UART data, what is the best approach: should I enable the INT_RDA interrupt? Or should I keep <INT_RDA> disabled and instead set the UART RX pin as an external such as <INT_CN | PIN_F2> and when the unit has woken-up, disable that interrupt and re-enable the INT_RDA interrupt?
I will start doing some tests but any suggestions are welcome.
Thanks again,
Ben |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Mon Aug 19, 2019 8:12 am |
|
|
Define the MCU's sleep state please, as there are a number of different sleep states. Deep sleep halts the clock. Doze halts the processor but leaves the clock running for the peripherals.
I haven't played with a UART and deep sleep, but if the clock is halted, the UART absolutely will miss a number of leading characters while the clock is started and subsequently stabilizes. If the sleep state is doze, then the UART is clocked and no data will be missed. |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Aug 19, 2019 9:47 am |
|
|
The MCU sleep state is from CCS's code and I use <sleep( SLEEP_FULL );>, whatever that does in the background.
I'll try to re-explain clearly point by point. Forget everything I've written from the original post to here.
Let's restart from scratch from here as I've stripped-down the wake-up code to the bear minimum and it's not waking-up correctly with #INT_RDA when the modem sends serial data (regardless if it's an incoming call or an incoming SMS)....
1- All external interrupts fire as expected and wake-up the unit no problem, INCLUDING the UART RX interrupt (RX on the MCU coming from the modem's TX pin)... BUT...
2- Beofre going to sleep, both the <INT_CN | UART_RX_PIN> and <INT_RDA> interrupts are enabled for **the same pin**, the first one is to trigger a state change interrupt and the other to trigger an #INT_RDA interrupt (not sure if both are needed though);
3- For UART RX to wake-up the MCU, I must either call the modem or send it an SMS;
4- When either of those two come-in (call or SMS), the modem transmits over its TX pin to the MCU's RX pin either "RING" (call) or "+CMT:info" (SMS);
5- When woken-up by SMS, I don't need to know (and don't care) what is the text or number that woke-up the unit, I just need it to wake-up the unit, that's it (e.g toggle the pin is good enough);
6- When woken-up by an incoming call, I don't care what the number is, I just want the unit to wake-up;
7- After the unit has woken-up, regardless how it wakes-up (external sensor, SMS or call), the unit does not do a full reboot, it simple re-initializes the MCU (not the modem) so that it can quickly resume operation and get back online;
8- After waking-up, although the modem is not rebooted from scratch, the reboot procedure will still issue a few basic commands to the modem to make sure it is responding;
PROBLEM: When an SMS or call comes-in, modem sends the appropriate data to the MCU (RING or +CMT) but as soon as the first basic modem initialization command is sent from the MCU to the modem, I can see the modem's response in my logs but the MCU does not fire its #INT_RDA interrupt. That's the problem. The #INT_RDA never fires therefore the initialization sequence fails.
I stripped-down my wake-up sequence to the bear minimum and here's what it looks like:
// Sleep NOW
sleep( SLEEP_FULL );
// ** UNIT IS SLEEPING **
** HERE, I TEXT THE UNIT OR CALL IT WHICH TRIGGERS THE UART RX PIN THEN WAKES-UP THE MCU **
// Wake-up - wait a few cycles
delay_cycles( 100 );
// Wake-up modem from sleep
output_low( MODEM_PIN_DTR_SLEEP );
delay_ms( 250 );
// Get state of each interrupt
unsigned long InterruptState = input( PIN_UART1_RX ) << 7 | // Bug in interrupt_active() for INT_CN pins so just read the state
( interrupt_active( INT_RDA ) << 6 ) |
( interrupt_active( INT_EXT0 ) << 5 ) |
( interrupt_active( INT_EXT1 ) << 4 ) |
( interrupt_active( INT_EXT2 ) << 3 ) |
( interrupt_active( INT_EXT3 ) << 2 ) |
( interrupt_active( INT_EXT4 ) << 1 );
// Print state of each input
[b] fprintf( MONITOR_SERIAL, "\n\rPIN_UART1_RX : %u -- UART RX pin state change", InterruptState >> 7 & 0x01 );
fprintf( MONITOR_SERIAL, "\n\rINT_RDA : %u -- UART RX data", InterruptState >> 6 & 0x01);
fprintf( MONITOR_SERIAL, "\n\rINT_EXT0 : %u -- Input 0 triggered", InterruptState >> 5 & 0x01);
fprintf( MONITOR_SERIAL, "\n\rINT_EXT1 : %u -- Input 1 triggered", InterruptState >> 4 & 0x01);
fprintf( MONITOR_SERIAL, "\n\rINT_EXT2 : %u -- Input 2 triggered", InterruptState >> 3 & 0x01);
fprintf( MONITOR_SERIAL, "\n\rINT_EXT3 : %u -- Input 3 detected", InterruptState >> 2 & 0x01);
fprintf( MONITOR_SERIAL, "\n\rINT_EXT4 : %u -- Input 4 stopped", InterruptState >> 1 & 0x01 );
// Clear CN interrupt flag (requires to be cleared this way due to bug in compiler)
#BIT CNIF=getenv("BIT:CNIF")
CNIF = FALSE;
delay_ms( 500 );
clear_interrupt( INT_RDA );
enable_interrupts( INT_DMA0 );
enable_interrupts( INT_UART1E );
enable_interrupts( INT_TIMER1 );
enable_interrupts( INT_TBE );
enable_interrupts( INT_RDA2 );
clear_interrupt( INT_DMA0 );
clear_interrupt( INT_UART1E );
clear_interrupt( INT_TBE );
clear_interrupt( INT_TIMER1 );
clear_interrupt( INTR_CN_PIN );
clear_interrupt( INT_RDA2 );
delay_ms( 500 );
enable_interrupts( GLOBAL );
delay_ms( 500 );
Here is the print-out (from Tera Term) of the above code when it wakes-up:
PIN_UART1_RX : 1 -- UART RX pin state change
INT_RDA : 1 -- UART RX data
INT_EXT0 : 0 -- Input 0 triggered
INT_EXT1 : 0 -- Input 1 triggered
INT_EXT2 : 0 -- Input 2 triggered
INT_EXT3 : 0 -- Input 3 triggered
INT_EXT4 : 0 -- Input 4 triggered
As you can see above, the pin state is correct and the RDA interrupt fired since data arrived, but...
From this point-on, the MCU re-initializes a few things, including a few basic commands that are sent to the modem and the modem responds just fine because I see the data going to the MCU but the INT_RDA never fires, although it is enabled therefore the whole unit sits there waiting because something prevents the INT_RDA interrupt from firing. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Mon Aug 19, 2019 10:21 am |
|
|
Have you tried using the UART's WAKE capability instead of the CN interrupt? [Bit 7 of the UxMODE register]
Can you do a read & dump (or even just flash an LED) of the UART's error flags, bits 1-3 of the UxSTA register? If you *don't* add "ERRORS" to your serial setup (#use rs232), then you're solely responsible clearing those errors as they arise. Any type of error will lock up the UART.
Depending on which UART you're using, the CN interrupt has a higher natural priority over UART2's interrupts, but not UART1. Therefore there's a potential for the CN interrupt to be serviced instead of the RDA interrupt, but of course only if both CN and RDA are simultaneously active and the UART's receive pin is still "routed to" the CN interrupt in software.
I get what you're doing and why but I think that it's your "mix & match" of the CN interrupt to awaken the processor then switchover to RDAx interrupt that is killing you. Since the UART has a wake feature, try using that instead of the Rube Goldberg CN approach and I think that things will work much better for you.
One last thing that might (maybe) be causing issues: sleep might be changing the UART's setup, or might be disabling it altogether. Another thing to try might be to re-initialize the UART after waking up - try that only if the WAKE feature doesn't give you any love. I say this because PMD (which I use extensively in low power applications) completely removes power from a peripheral and you have to then repeat the peripheral setup again once you wake. That nuance has bitten me before. There might be an undocumented errata where deep sleep is causing the UART to lose its setting (but this is probably not very likely). |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19364
|
|
Posted: Mon Aug 19, 2019 11:04 am |
|
|
Simple question.
You have got:
setup_uart(UART_WAKEUP_ON_RDA, YOUR_UART_STREAM);
in your code?.
The UART by default _will not_ respond to an edge when asleep. The
WAKE but in the UART needs to be set to enable wake-up. This command
sets this.
Depending on your baud rate, you may receive several corrupted characters
when the chip wakes (the data sheet warns that the first character may be
corrupted, but in fact at high rates several will be). |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Aug 19, 2019 11:12 am |
|
|
ha! ha! I didn't know who Rube Goldberg was and I Googled him! That's funny!
To be honest, I've never used the WAKE thing, I didn't even knew it existed. I'll have to read through it.
I'll also put the #use rs232( UART1, baud=UART_SPEED, parity=N, bits=8, STREAM=MODEM_SERIAL, ERRORS ) back in there. And as you can see, I do use the <ERRORS> flag.
I should also point that if I use only <INT_RDA> and don't use <INT_CN | UART_RX_PIN>, then the MCU never wakes-up. So it almost points as to if INT_RDA cannot be used to wake-up the MCU?
So this is strange as well. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Mon Aug 19, 2019 11:24 am |
|
|
As Ttelmah said, unless you put UART_WAKEUP_ON_RDA in your #use rs232 setup, the UART is incapable of waking the processor. |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Aug 19, 2019 11:25 am |
|
|
Ah! I hadn't seen his response although my comment to your post is after him!
Ok I'll try that... |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 Location: Ottawa, Ontario, Canada
|
|
Posted: Mon Aug 19, 2019 11:31 am |
|
|
Actually, so in my project's main .h file, I have <#use rs232( UART1, baud=UART_SPEED, parity=N, bits=8, STREAM=MODEM_SERIAL, ERRORS )>
But then in my initialization routine - the one that is called at main power-up but also at wake-up time - should start with <setup_uart( UART_WAKEUP_ON_RDA, MODEM_SERIAL );>?
Therefore I don't need to use the interrupt for <INT_CN | UART_RX_PIN> but only <INT_RDA>?
I just want to make sure I don't over-do this and have too much unnecessarry code... |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|