CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Interrupt problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

Interrupt problem
PostPosted: Thu Jan 12, 2006 4:42 am     Reply with quote

Hi all .

I need help for understanding interrupt .
I want to insert this code (see also the complete program)
for to put command on rs232.
I don't be able to turn on one led every time the interrupt occur.
the interrupt occour when i recive the string after every command.

static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};

I put six command on 232 and after every one the led will turn on
for indicate the correct reception, the loop continue always.

Somebody can help me thanks.
Code:



 for(x=0; x<=5; x++)
         {

         do{
            output_high(LED6);
            delay_ms(200);
            output_low(LED6);
            delay_ms(200);
           }while(input(PUSH_BUTTON));
     
  delay_ms(1000);
  output_b(0x00);
  output_low(RXLED);
 
// STREAM 1,2,3,4,5,6
   
    y= TABLE1[x];
    w= TABLE2[x];

  printf("\x2");
  printf("0001wdloa;");
  printf("%c",w);
  printf(";");
  printf("%c",y);
  printf("\x3");

//RX   STX,0,0,0,1,1,SEMICOLON,AD,ETX   RXLED ON

   output_high(LED1);
   delay_ms(2000);

         }//for


Code:
#if defined(__PCH__)
#include <18F452.h>
#include <string.H> 

#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#endif

#include <input.c>

#define     STX        0x02  // Start of Transmition
#define     ETX        0x03  // End of Transmition
#define     AD         0xAD 
#define     SEMICOLON  0x3B

#define     LED1         PIN_B0
#define     LED6         PIN_B5
#define     RXLED        PIN_A2
#define     PUSH_BUTTON  PIN_D0

//------------------------------------------------------------------------------

#define     BUFFER_SIZE 9

//------------------------------------------------------------------------------
 
#DEFINE  BUFFER_COMPARE

//------------------------------------------------------------------------------

// GLOBALS
static int8 char_rcved, data_valid, next_in;
static int8 buffer_overflow, stream_complete;
static int8 sermssg[BUFFER_SIZE];
int x;
char y,w;

BYTE CONST TABLE1[7] ={' ','\x80','\x81','\x82','\x83','\x84'};
BYTE CONST TABLE2  [7] ={'1','2','3','4','5','6'};
//--------------------------------------------------------------------------------

static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};

//--------------------------------------------------------------------------------
// SETTINGS
   set_tris_b(0x00);
   set_tris_d(0b11111111);
   set_tris_a(0b00000000);

 //------------------------------------------------------------------------------
#INT_RDA
void isr_serial_rcv()
{
  char_rcved = getc(); // Get the incoming char

  if ( char_rcved == STX ) 
     { next_in = 0;        // Init the index
       data_valid = TRUE;  // Enable buffering
       buffer_overflow = FALSE;
     }

  if ( data_valid )       
     { sermssg[next_in] = char_rcved;
       next_in++;           

       if ( next_in > BUFFER_SIZE ) // String longer than expected
          { data_valid = FALSE; // Stop buffering
            buffer_overflow = TRUE;
          }

       if ( char_rcved == ETX )
          { data_valid = FALSE; // Stop buffering
            stream_complete = TRUE;
          }
     }
}
//--------------------------------------------------------------------------------
 
void main()
{
   delay_ms(400);     
   stream_complete = FALSE;
   enable_interrupts(GLOBAL);

     
   while(1)
        {
         enable_interrupts( INT_RDA );
        do{
       //nothing                       
          }while ( !stream_complete );
 
//--------------------------------------------------------------------------------
         
         if ( stream_complete )
           {
               stream_complete = FALSE;  // IMPORTANT: If not the program re-enter
           

         if ( !buffer_overflow )
               {
                 disable_interrupts( INT_RDA );
         
                   
#IFDEF BUFFER_COMPARE  //////////////////////////////////////////////////////////

         if (strcmp(stringa,sermssg))
                    {
                     output_high(RXLED);
                    }
#ENDIF //////////////////////////////////////////////////////////////////////////
   

                } // if ( !buffer_overflow )

        if ( buffer_overflow )
           {// something wrong related to incoming string
             output_b(0xff);
             delay_ms(3000);    // Just to see a change in output_b
             buffer_overflow = FALSE; // clear the fault !!!!
           } 
 
          }   // if ( stream_complete )

        }     // while(1)
 
}     // void main()
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jan 12, 2006 3:12 pm     Reply with quote

Your main problem is that you are doing string operations, but you
never terminate the strings with a byte of 0x00.

In your first string here, you don't terminate it. It actually is terminated
but it's just by luck. The 'static' keyword will set all un-initialized ram
values to 0x00. So you do, by luck, get this string to be terminated.
Quote:
static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};


In your next string here, which is built from incoming RS232 chars,
you notice when the end of a string is received, but you never put a
final 0x00 byte at the end of the string.
Quote:
#INT_RDA
void isr_serial_rcv()
{
.
.
.
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
stream_complete = TRUE;
}

}


So later, you are doing string operations here, but neither of the
arguments for strcmp() are actually strings. That's because they
are missing the final 0x00 at the end of each one. So your program
operation is unpredictable at this point. It may crash.
Quote:
if (strcmp(stringa,sermssg))
{
output_high(RXLED);
}
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Fri Jan 13, 2006 8:12 am     Reply with quote

Excuse me I don't understand so much what you want tell me .

Quote:

Your main problem is that you are doing string operations, but you
never terminate the strings with a byte of 0x00.


Why i must terminate the string with 0x00 ?

Quote:

The 'static' keyword will set all un-initialized ram
values to 0x00.


I must assign space in ram for my string?

How I can terminate the string with 0x00?
mcafzap



Joined: 07 Sep 2003
Posts: 46
Location: Manchester, UK

View user's profile Send private message

PostPosted: Fri Jan 13, 2006 9:51 am     Reply with quote

In 'C'strings are ended with '\0' otherwise the various functions would need to know the length of the strings.

To add this to your code you could add this line (untested) :

Code:

existing interrupt code...

    if ( char_rcved == ETX )
          { data_valid = FALSE; // Stop buffering
 

         sermssg[next_in] = '\0';


            stream_complete = TRUE;
          }
     }
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 13, 2006 1:40 pm     Reply with quote

In my eagerness to find a string problem, I made a mistake.
The array below is actually a string of length = 1, because the
2nd character in the array is 0x00. The only char in it is STX.
static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};

Is that your intention ?

Or, are they supposed to be ASCII characters ? In that case,
you should initialize them like this, with the 0 and one in single
quotes. Doing that will create ASCII values for 0 and 1 in the array.
Also add a zero on the end to terminate the string.
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX, 0};

If you want to use your original array values, then you should use the
memcmp() function to compare the arrays. You have to specify
the number of bytes to be compared, if you use memcmp().
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Mon Jan 16, 2006 3:56 am     Reply with quote

I suppose to be ascii characters in the string.

static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,0};

I have insert the function memcmp( s1, s2, n )
Code:

#IFDEF BUFFER_COMPARE  //////////////////////////////////////////////////////////

         if (memcmp(stringa,sermssg,9))
                    {
                     output_high(RXLED);



It return 0 if stringa = sermssg .

How I can use the return 0 of function memcmp ?

I have insert also the string
Code:

 if ( char_rcved == ETX )
          { data_valid = FALSE; // Stop buffering
            sermssg[next_in] = '\0';
            stream_complete = TRUE; 


is necessary to add this ??
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Mon Jan 16, 2006 9:16 am     Reply with quote

Quote:

is necessary to add this ??


If you define your string as:
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX, 0};
as PCM Programmer suggest, it is not necesary.

But if you define your string as:
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX};
mcafzap suggest that while receiving the string and detect the ETX char,
the statement

sermssg[next_in] = '\0';

'add' the null ('\0' or 0x00) character at the end of the string.

In C an array of any finite sequence of charaters ending with '\0' is formally a string,
so a null char is needed at the end for further comparations or actions with the string.
In other words, memcmp and others functions that handle strings expect a '\0' as string delimiter.

Quote:

How I can use the return 0 of function memcmp ?


In your statement:

if(memcmp(stringa,sermssg,9))

memcmp compare the first 9 characters of the arrays and return:

Code:

 <0: if  stringa <  sermssg
  0: if  stringa == sermssg
 >0: if  stringa >  sermssg



Humberto
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Wed Jan 18, 2006 10:02 am     Reply with quote


Humberto says



Quote:


sermssg[next_in] = '\0';

'add' the null ('\0' or 0x00) character at the end of the string.


I decide to insert ,in the code, not in the answer of machine,(The machine respond only with 9 characters ETX is the last)the following code.
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'};

and
Code:
 if ( char_rcved == ETX )
          { data_valid = FALSE; // Stop buffering
            sermssg[next_in] = '\0';
            stream_complete = TRUE;


is correct ?

Quote:
memcmp compare the first 9 characters of the arrays and return:


What is the correct sintax for compare ?

if (memcmp(stringa,sermssg,9)) ==0;

{
output_high(RXLED);

}

Quote:

In other words, memcmp and others functions that handle strings expect a '\0' as string delimiter.


But if the function expect '/0'
if (memcmp(stringa,sermssg,9)) ==0;
is not just correct .
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Wed Jan 18, 2006 1:21 pm     Reply with quote

I think you have missunderstood the difference between '0' and '\0'
'\0' is equal to 0x00
'0' is equal to 0x30 wich is the ASCII representation of the decimal number '0'

A string must end with '\0' (null)
The result of a comparation could be '0' (zero)

Quote:

But if the function expect '/0'
if (memcmp(stringa,sermssg,9)) ==0;
is not just correct .

Now I hope you understand that this comment is out of focus.


Quote:

I decide to insert ,in the code, not in the answer of machine,(The machine respond only with 9 characters ETX is the last)


The received packet is:
STX,'0','0','0','1','1',SEMICOLON,AD,ETX
But to be a string, it should end with '\0'.

Using the following code at receiving time, inside the #INT_RDA handler:
Code:
 
 if ( char_rcved == ETX )
   { data_valid = FALSE; // Stop buffering
      sermssg[next_in] = '\0';
      stream_complete = TRUE; 
   }

would add the (needed) '\0' at the end of the received packet. Now it would look like this:
STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'
which is technically a string (in C)

Quote:

What is the correct sintax for compare ?


Take a look at the function prototype that you are using:

Code:

signed int memcmp(void * s1,char *s2,size_t n)
{
char *su1, *su2;
for(su1=s1, su2=s2; 0<n; ++su1, ++su2, --n)
   {
    if(*su1!=*su2)
       return ((*su1<*su2)?-1:+1);
   }
   return 0;
}


and you will see that it return an signed integer

so you can compare strings in this way:

Code:

void CompareStrings()
{
signed int8  compare_result;

   compare_result = memcmp(stringa,sermssg,9);

  if(compare_result == 0)   
    {
     .........
    }
 
  if(compare_result < 0)
    {
     .........
    }
 
  if(compare_result > 0)
    {
     .........
    }
}



Humberto
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Tue Feb 21, 2006 4:06 am     Reply with quote

Thanks Humberto

The code working well , excuse me for my misunderstood.

There is only one problem.
When i power on the remote, the interrupts goes on one time for each one .
Why ? This is part of my main .

Code:

void main()
{
    delay_ms(1000);               // Aspetto che il power supply vada a regime. 
       
   
   set_tris_d(0x00);
   set_tris_a(0x00);
   set_tris_b(0b00000111);
   
   port_b_pullups(TRUE);
     
   enable_interrupts(int_EXT);
   enable_interrupts(int_EXT1);
   enable_interrupts(int_EXT2);
   
   ext_int_edge(H_TO_L);
   ext_int_edge(1,H_TO_L);
   ext_int_edge(2,H_TO_L);
 
   enable_interrupts(GLOBAL);
//-----------------------------------------------------------------------------

   stream_complete = FALSE;

//----------------------------------------------------------------------------- 
 while(1)
        {
         enable_interrupts( INT_RDA );

         do
           {                       // Fai qualcosa mentre aspetti i dati.
           
            output_high(WAITLED);
            delay_ms(200);
            output_low(WAITLED);
            delay_ms(200);

           }while ( !stream_complete );        //Continua fino a che stream_complete e' FALSE


Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Tue Feb 21, 2006 8:08 am     Reply with quote

Quote:

When i power on the remote, the interrupts goes on one time for each one.


We doesn't know what are you talking about. You didn't mention anything regarding a remote.


Humberto
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Tue Feb 21, 2006 9:13 am     Reply with quote

The remote rs 232 perform this operations.

Transmit six different command by means # int_ext and other two command by # int_ext1 and # int_ext2 to one slave board.
Slave answer always the same string to confirm the correct action request.
This string is compared for led indication.


Code:


#if defined(__PCH__)
#include <18F452.h>
#include <string.h>                                        // Per usare strcmp.

#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#endif

#include <input.c>


#define     STX        0x02                                // carattere STX   
#define     ETX        0x03                                // carattere ETX 
#define     AD         0xAD                                // carattere 173  ¡
#define     SEMICOLON  0x3B                                // carattere 3b   ;
 
#define     BUTTON1        PIN_B0                          // Pulsante comando 1
#define     BUTTON2        PIN_B1                          // Pulsante comando 2
#define     BUTTON3        PIN_B2                          // Pulsante comando 3
#define     LED1           PIN_D0                          // 
#define     LED2           PIN_D1                       // 
#define     LED3           PIN_D2                       // 
#define     LED4           PIN_D3                       // 
#define     LED5           PIN_D4                       // 
#define     LED6           PIN_D5                       // 

#define     LEDB           PIN_D6                       // 
#define     LEDC           PIN_D7                          // 

#define     LEDA           PIN_A0                          // 
#define     WAITLED        PIN_A1                          // 
//------------------------------------------------------------------------------

#define     BUFFER_SIZE 9

//------------------------------------------------------------------------------

//                VARIABLES GLOBALS

static int8 char_rcved, data_valid, next_in;
static int8 buffer_overflow, stream_complete;
static int8 sermssg[BUFFER_SIZE];
char k;
char y,w;
signed int x=-1;
int interrupt_flag,z;

static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'};

BYTE CONST TABLE1[6] ={'1','2','3','4','5','6'};
BYTE CONST TABLE2[6] ={'\xFF','\x80','\x81','\x82','\x83','\x84'};

//-------------------------------------------------------------------

void CompareStrings()
{
  signed int8  compare_result;
 
  delay_ms(300);                     // Per vedere tra una ricezione e l'altra .

//-------------------------------------------------------------------Cosa ricevo ?

//for ( z = 0; z<BUFFER_SIZE; z++)   // < Perche' parto da zero cosi l'ultimo
//    { k= sermssg[z];               // carattere e' ETX.
//      printf("%c",k);                     
//    } 

//-------------------------------------------------------------------
   compare_result = memcmp(stringa,sermssg,9);

  if(compare_result == 0)   
    {
     output_high(LEDA);
     
    }
 
  if(compare_result < 0)
    {
     output_high(WAITLED);
    }
 
  if(compare_result > 0)
    {
     output_high(WAITLED);
    } 
   }

//------------------------------------------------------------------

void Comando()
     {
      output_a(0x00);
      x++;
     
    if (x<=5)
          {
    y= TABLE2[x];
    w= TABLE1[x];

  printf("\x2");
  printf("0001wdloa;");
  printf("%c",w);
  printf(";");
  printf("%c",y);
  printf("\x3");
           } 
           else {
                x=-1;
                }
    }//void Profilo 

//------------------------------------------------------------------Led   

void Led()
 
        {
  if
        (x==0){
        output_low(LED6);
        output_high(LED1);
        }
else if
        (x==1){
        output_low(LED1);
        output_high(LED2);
        }
else if
        (x==2){
        output_low(LED2);
        output_high(LED3);
        }
else if
        (x==3){
        output_low(LED3);
        output_high(LED4);
        }
else if
        (x==4){
        output_low(LED4);
        output_high(LED5);
        }
else if
        (x==5){
        output_low(LED5);
        output_high(LED6);
        }
}

//------------------------------------------------------------------------
#INT_RDA
void isr_serial_rcv()
{
   
  char_rcved = getc();           // Memorizza caratteri ricevuti.

  if ( char_rcved == STX ) 
     { next_in = 0;         
       data_valid = TRUE; 
       buffer_overflow = FALSE;
     }

  if ( data_valid )       
     { sermssg[next_in] = char_rcved;
       next_in++;         

 
  if ( char_rcved == ETX )
     { data_valid = FALSE;
       sermssg[next_in] = '\0';   
       stream_complete = TRUE;
     }
   }                                 // if( data_valid)
}                                    // void isr_serial_rcv()

//------------------------------------------------------------------
# int_ext
void EXT_isr(void)
        {
       
         while(!input(BUTTON1));
         
            Comando();
            Led();
                  }
//------------------------------------------------------------------
# int_ext1
EXT1_isr()
         
        {
          while(!input(BUTTON2));
  {   
      output_low(LEDB);
      output_low(LEDA); 
      printf("\x4");
      output_high(LEDC);
  }
}

//------------------------------------------------------------------
# int_ext2
EXT2_isr()
         
        {
          while(!input(BUTTON3));
{     
      output_low(LEDC);
      output_low(LEDA);
      printf("\x5");
      output_high(LEDB);
  }
}
//-----------------------------------------------------------------------------

void main()
{
    delay_ms(1000);               // Aspetto che il power supply vada a regime. 
     
   set_tris_d(0x00);
   set_tris_a(0x00);
   set_tris_b(0b00000111);
   
   port_b_pullups(TRUE);
     
   enable_interrupts(int_EXT);
   enable_interrupts(int_EXT1);
   enable_interrupts(int_EXT2);
   
   ext_int_edge(H_TO_L);
   ext_int_edge(1,H_TO_L);
   ext_int_edge(2,H_TO_L);
 
   enable_interrupts(GLOBAL);
//-----------------------------------------------------------------------------

   stream_complete = FALSE;

//----------------------------------------------------------------------------- 
 while(1)
        {
         enable_interrupts( INT_RDA );

         do
           {                       // Fai qualcosa mentre aspetti i dati.
           
            output_high(WAITLED);
            delay_ms(200);
            output_low(WAITLED);
            delay_ms(200);

           }while ( !stream_complete );        //Continua fino a che stream_complete e' FALSE

//-----------------------------------------------------------------------------
       
            if ( stream_complete )
           {
            stream_complete = FALSE;  // IMPORTANTE: Se no il programma rientra in CompareStrings();         

            disable_interrupts( INT_RDA );
           
            CompareStrings();
 
      }   // if ( stream_complete )

  }     // while(1)

}     // void main()

//------------------------------------------------------------------------------------


This code workig well but when i power on interrupts produce three command ,one for each one ,on port .

Why ? Thanks in advance.
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Tue Feb 21, 2006 12:28 pm     Reply with quote

Quote:

This code workig well but when i power on interrupts produce three command ,one for each one ,on port .


I assume you want to say "when I enable interrupts..."

You used the built-in pull ups resistor in Port_B:

port_b_pullups(TRUE);

so, you should read a voltage close to +5V on Pins B0, B1 and B2.

1) Are those voltages OK ?
2) Does this voltage get a value close to 0V when the respective switch is pressed ?



Humberto
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Feb 21, 2006 6:21 pm     Reply with quote

Code:
   enable_interrupts(int_EXT);
   enable_interrupts(int_EXT1);
   enable_interrupts(int_EXT2);
   
   ext_int_edge(H_TO_L);
   ext_int_edge(1,H_TO_L);
   ext_int_edge(2,H_TO_L);
 
   enable_interrupts(GLOBAL);
I don't know, but I find the sequence of commands a bit tricky. First you arm the interrupts and then you change the conditions for triggering the interrupt, depending on the deep internals of the PIC hardware this might work as you expect or it activates all three interrupts. I wouldn't take any chances and reverse the sequence of commands:
Code:
   ext_int_edge(H_TO_L);
   ext_int_edge(1,H_TO_L);
   ext_int_edge(2,H_TO_L);
 
   enable_interrupts(int_EXT);
   enable_interrupts(int_EXT1);
   enable_interrupts(int_EXT2);
   
  enable_interrupts(GLOBAL);


To be really sure you could even add a clear_interrupt command before enabling the global interrupt flag.
Sebastian



Joined: 01 Dec 2003
Posts: 21
Location: Milan Italy

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 22, 2006 6:53 am     Reply with quote

Thanks you Humberto , ckielstra i have add the following code
Code:

#if defined(__PCH__)

#bit ext_int0 = 0xFF2.1  // INTCON  REGISTER ADDRESS FF2H  BIT 0
#bit ext_int1 = 0xFF0.0  // INTCON3 REGISTER ADDRESS FF0H  BIT 0
#bit ext_int2 = 0xFF0.1  // INTCON3 REGISTER ADDRESS FF0H  BIT 1

#endif


and this in main

Code:

  #asm
BCF ext_int0
BCF ext_int1
BCF ext_int2
   #endasm


Now the interrupts working well.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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