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

Sabertooth 2x25 Driver

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Sergeant82d



Joined: 01 Nov 2009
Posts: 55
Location: Central Oklahoma

View user's profile Send private message

Sabertooth 2x25 Driver
PostPosted: Tue Jul 19, 2011 12:35 am     Reply with quote

Here is a driver for Dimension Engineering's Sabertooth line of motor controllers.

See the Dimension Engineering web page and manuals for more information www.dimensionengineering.com

Edited 07 July 2013: Minor changes to header comments only - no changes to driver files.

Edited 07 June 2012: Major changes -
- Separated header info from source file
- Added return value to each user function to report success
- Split motor command function into two - one to control each motor separately, and another to use the mixed-mode commands

Edited 22 September 2011: Renamed a few constants to better reflect their purpose.

Edited 28 August 2011: I standardized the function comments - no changes to the driver itself.

Edited 23 August 2011: I have cleaned up and made the driver functions more consistent in their arrangement, along with fixing a couple of minor bugs which could have caused unpredictable results.


sabertooth_2x25_driver.h

Code:


/**********************************************************************************************
 *
 * Sabertooth_2x25_Driver.h
 * Version 2.0.2
 * 07 July, 2013
 *
 * Brad Hedges
 * H & H Enterprises
 * Stratford, Oklahoma
 *
 **********************************************************************************************
 **********************************************************************************************
 *
 * This is a multi-purpose device driver to operate the Dimension Engineering Sabertooth series
 * of H-Bridge motor controllers. These can be used to control permanent magnet DC motors
 * between 6 & 30 volts, up to 25 amps continuous and 50 amps surge.
 *
 * This driver works in the "Packetized Serial" mode, which must be set with the DIP
 * switches on the controller hardware. The driver defaults to operating only one
 * Sabertooth, using the lowest physical address of 128. The address is configurable in
 * the driver by assigning the address value to the constant "MOTOR_DRIVER_ADDRESS_x".
 *
 * The driver is written in the C language for Microchip PIC microcontrollers using CCS's
 * PIC-C Compiler, and was developed using version 4.120 of that compiler. I have also used it
 * with 32-bit PICs, using Microchip's C32 compiler.
 *
 * It should be easily convertible to other microcontrollers and compilers with minimal effort. I have
 * annotated the three lines which would have to be modified for a different compiler or
 * processor architecture.
 *
 * Dimension Engineering's web site is at:      www.dimensionengineering.com
 * CCS's web site is:                           www.ccsinfo.com
 * Microchip's web site:                        www.microchip.com
 *
 *********************************************************************************************/


#ifndef sabertooth_2x25_driver_h
    #define sabertooth_2x25_driver_h

#include <stdio.h>                  // Need to be able to use standard output "putchar" command
#include <stdint.h>                 // Include your standard types definition file to accomodate the C99 uint_x types

#define FALSE   0
#define TRUE    1


/**********************************************************************************************
 **********************************************************************************************
 * This is the only section that should require modification for non-PIC/non-CCS Compiler usage
 *********************************************************************************************/

 /* In this section you must make modifications to suit both your hardware, and your compiler
  *
  * Assign name to a MOTOR_STOP output pin for emergency stop routines
  *
  * The two macros are for use in your application code to halt all movement or
  * re-enable it, using the MOTOR_STOP pin defined above.
  *
  * The Sabertooth requires only that a control pin be pulled low to completely disable
  * the two motor outputs, and if unused, it can be left floating (you don't have to use that pin)
  *
  * Possible uses are bumper switches or other sensors, or during startup when you don't
  * want the motors enabled until all systems are properly initialized */


/* TODO: Create a driver-wide #define file to include from a system hardware file, rather than assigning hardware
 *       in this header file. The intent is to assign all hardware I/O in "hardware.h", rather than
 *       in separate/distributed files....  */

#ifdef __PICC__                                                                                                         /** CCS Compiler */

    #define MOTOR_STOP                   PIN_D5

    #define mSTOP_ALL_MOTORS             output_low(MOTOR_STOP);
    #define mRESTART_ALL_STOPPED_MOTORS  output_high(MOTOR_STOP);

#endif

#ifdef __C32__                                                                                                          /** Microchip PIC 32-Bit Compiler */

    #define MOTOR_STOP                   1 << 10                        //PORTBbits.RB10

    #define mSTOP_ALL_MOTORS             mPORTBClearBits( MOTOR_STOP ) // output_low(MOTOR_STOP);
    #define mRESTART_ALL_STOPPED_MOTORS  mPORTBSetBits( MOTOR_STOP )   // output_high(MOTOR_STOP);

#endif


/**********************************************************************************************
 * End of the only section that should require modification for non-PIC/non-CCS Compiler usage
 **********************************************************************************************
 *********************************************************************************************/





/**********************************************************************************************
 * SETUP INFORMATION
 *********************************************************************************************/

    /* You must send the autobauding character to your Sabertooth during program initialization,
     * before sending any commands to the device.
     *
     * This must be done each time the device powers up. */

    #define mSEND_AUTOBAUD               putchar(0xAA)


    /* Each serial command to the hardware is checked for validity by the on-board processor */

    #define CRC_MASK                     0b01111111


    /* Use desired hardware address, per hardware DIP switch settings */

    #define MOTOR_DRIVER_ADDRESS_1       128
    #define MOTOR_DRIVER_ADDRESS_2       129
    #define MOTOR_DRIVER_ADDRESS_3       130
    #define MOTOR_DRIVER_ADDRESS_4       131
    #define MOTOR_DRIVER_ADDRESS_5       132
    #define MOTOR_DRIVER_ADDRESS_6       133
    #define MOTOR_DRIVER_ADDRESS_7       134
    #define MOTOR_DRIVER_ADDRESS_8       135


/**********************************************************************************************
 * COMMANDS
 *********************************************************************************************/


    #define COMMAND_LOW_LIMIT            0                            // For bounds checking purposes only

    #define DRIVE_FORWARD_1              0
    #define DRIVE_REVERSE_1              1

    #define SET_MIN_VOLTAGE              2
    #define SET_MAX_VOLTAGE              3

    #define DRIVE_FORWARD_2              4
    #define DRIVE_REVERSE_2              5

    #define DRIVE_MOTOR_1_7_BIT          6
    #define DRIVE_MOTOR_2_7_BIT          7

    #define DRIVE_FORWARD_MIXED          8
    #define DRIVE_REVERSE_MIXED          9
    #define DRIVE_TURN_RIGHT_MIXED       10
    #define DRIVE_TURN_LEFT_MIXED        11

    #define DRIVE_FWD_REV_7_BIT          12
    #define DRIVE_TURN_7_BIT             13

    #define SET_SERIAL_TIMEOUT           14
    #define SET_BAUD_RATE                15

    #define SET_RAMPING_RATE             16
    #define SET_DEADBAND                 17

    /* If any more commands are added by the manufacturer in the future, increase
     * COMMAND_HIGH_LIMIT to the highest command number in that new command set.
     * As with the COMMAND_LOW_LIMIT, this is only used for bounds checking in a function.
     *
     * Yes, we could enumerate the commands, and that works better in MPLAB 8 debugging,
     * but the macro viewer capability in the new MPLABX IDE that I am using is so neat
     * that I changed it back to separate #defines so I could use it.
     *
     * Your call. 8^)  */

    #define COMMAND_HIGH_LIMIT           17


/**********************************************************************************************
 * COMMAND DATA
 *********************************************************************************************/

    #define BAUDRATE_2400                1
    #define BAUDRATE_9600                2
    #define BAUDRATE_19200               3
    #define BAUDRATE_38400               4
    #define DEFAULT_BAUDRATE             BAUDRATE_9600

    #define MAX_MINIMUM_VOLTAGE          120
    #define MIN_MINIMUM_VOLTAGE          0
    #define DEFAULT_MINIMUM_VOLTAGE      0

    #define MAX_MAXIMUM_VOLTAGE          128
    #define MIN_MAXIMUM_VOLTAGE          0
    #define DEFAULT_MAXIMUM_VOLTAGE      0

    #define MAX_SERIAL_TIMEOUT           50
    #define MIN_SERIAL_TIMEOUT           0
    #define DEFAULT_SERIAL_TIMEOUT       0

    #define MAX_RAMPING_VALUE            80
    #define MIN_RAMPING_VALUE            0
    #define DEFAULT_RAMPING_VALUE        1

    #define MAX_DEADBAND                 127
    #define MIN_DEADBAND                 0
    #define DEFAULT_DEADBAND             3


/**********************************************************************************************
 * FUNCTION PROTOTYPES
 **********************************************************************************************
 *
 * *** NOTE *** If using the CCS Compiler, and only one single Sabertooth controller, you do not need the "address"
 *              variable. It is only needed if you are sending commands to more than one controller, or
 *              if you are using a compiler (such as Microchip's Cx/XCx series) which does not allow operator overloading.
 *
 *********************************************************************************************/


    uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, uint8_t command2, uint8_t speed2, uint8_t address );
   
    uint8_t control_motors_mixed ( uint8_t command, uint8_t speed, uint8_t address );

    uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, uint8_t address );

    uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, uint8_t address );

    uint8_t set_serial_timeout ( uint8_t desired_timeout_period, uint8_t address );

    uint8_t set_baudrate ( uint8_t desired_baudrate, uint8_t address );

    uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, uint8_t address );

    uint8_t set_deadband_range ( uint8_t desired_deadband, uint8_t address );
   
   
#endif

/**********************************************************************************************
 * END OF SABERTOOTH 2x25 HEADER
 *********************************************************************************************/




sabertooth_2x25_driver.c

Code:


/**********************************************************************************************
 *
 * Sabertooth_2x25_Driver.c
 * Version 2.0.2
 * 07 July, 2013
 *
 * Brad Hedges
 * H & H Enterprises
 * Stratford, Oklahoma
 *
 **********************************************************************************************
 **********************************************************************************************
 *
 * This is a multi-purpose device driver to operate the Dimension Engineering Sabertooth series
 * of H-Bridge motor controllers. These can be used to control permanent magnet DC motors
 * between 6 & 30 volts, up to 25 amps continuous and 50 amps surge.
 *
 * This driver works in the "Packetized Serial" mode, which must be set with the DIP
 * switches on the controller hardware. The driver defaults to operating only one
 * Sabertooth, using the lowest physical address of 128. The address is configurable in
 * the driver by assigning the address value to the constant "MOTOR_DRIVER_ADDRESS_x".
 *
 * The driver is written in the C language for Microchip PIC microcontrollers using CCS's
 * PIC-C Compiler, and was developed using version 4.120 of that compiler. I have also used it
 * with 32-bit PICs, using Microchip's C32 compiler.
 *
 * It should be easily convertible to other microcontrollers and compilers with minimal effort. I have
 * annotated the three lines which would have to be modified for a different compiler or
 * processor architecture.
 *
 * Dimension Engineering's web site is at:      www.dimensionengineering.com
 * CCS's web site is:                           www.ccsinfo.com
 * Microchip's web site:                        www.microchip.com
 *
 *********************************************************************************************/


#include "sabertooth_2x25_driver.h"



/**********************************************************************************************
 * Function:        uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, \
 *                                               uint8_t command2, uint8_t speed2, \
 *                                               uint8_t address )
 *
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the commands to the send_command function,
 *                      and then to the serial port
 * Side Effects:    None
 * Overview:        Checks commands for validity, and passes them to the serial port
 * Notes:           This function is valid for Sabertooth Commands 0, 1, 4 - 7
 *                  These commands are for controlling two motors with individual settings, a single motor at a time
 *
 *                      Individual Motor Commands:
 *                          0:  Drive Forward      Motor 1
 *                          1:  Drive Reverse      Motor 1
 *                          4:  Drive Forward      Motor 2
 *                          5:  Drive Reverse      Motor 2
 *                          6:  Drive 7-Bit        Motor 1
 *                          7:  Drive 7-Bit        Motor 2
 *
 *********************************************************************************************/

uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, \
                             uint8_t command2, uint8_t speed2, \
                             uint8_t address ) {
// = MOTOR_DRIVER_ADDRESS_1 ) { // If your compiler allows overloading, feel free to un-comment the assignment
// and move it immediately after the "address" variable
    if ( ( command1 < COMMAND_LOW_LIMIT || command1 > DRIVE_MOTOR_2_7_BIT ) || \
         ( command2 < COMMAND_LOW_LIMIT || command2 > DRIVE_MOTOR_2_7_BIT ) ) {

   /*     Set error code for invalid command
    *     Call a user error function to do whatever your application requires, such as:
    *         mSTOP_ALL_MOTORS;  */
        return FALSE;
    }

    else {
        send_command ( command1, speed1, address );
        send_command ( command2, speed2, address );
//      Set error code for no error
        return TRUE;
    }
}



/**********************************************************************************************
 * Function:        uint8_t control_motors_mixed ( uint8_t command, uint8_t speed1, uint8_t address )
 *
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the commands to the send_command function,
 *                      and then to the serial port
 * Side Effects:    None
 * Overview:        Checks commands for validity, and passes them to the serial port
 * Notes:           This function is valid for Sabertooth Commands 8 - 13
 *                  These commands are for controlling two motors simultaneously
 *
 *                      Mixed Mode Commands:
 *                          8:  Drive Forward      Mixed Mode
 *                          9:  Drive Reverse      Mixed Mode
 *                          10: Turn Right         Mixed Mode
 *                          11: Turn Left          Mixed Mode
 *                          12: Drive Forwards/Reverse     7 bit mode
 *                          13: Turn Left/Right            7 bit mode
 *
 *********************************************************************************************/

uint8_t control_motors_mixed ( uint8_t command, uint8_t speed, uint8_t address ) {

    if ( command < DRIVE_FORWARD_MIXED || command > DRIVE_TURN_7_BIT ) {

   /*     Set error code for invalid command
    *     Call a user error function to do whatever your application requires, such as:
    *         mSTOP_ALL_MOTORS;
    *         return;   */
        return FALSE;
    }

    else {
        send_command ( command, speed, address );
//      Set error code for no error
        return TRUE;
    }
}


/**********************************************************************************************
 * Function:        uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, \
 *                                                           uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    None
 * Overview:        Checks command for validity, and passes it to the serial port
 * Notes:           This function is valid for Sabertooth Command 2
 *********************************************************************************************/

uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, uint8_t address ) {

    uint8_t new_min_voltage = DEFAULT_MINIMUM_VOLTAGE;

    if ( desired_minimum_voltage < MIN_MINIMUM_VOLTAGE || \
         desired_minimum_voltage > MAX_MINIMUM_VOLTAGE ) {

            new_min_voltage = DEFAULT_MINIMUM_VOLTAGE;
            return FALSE;                                    // Set error code for error
    }

    else {
        new_min_voltage = desired_minimum_voltage;
    }

    send_command ( SET_MIN_VOLTAGE, new_min_voltage, address );
    return TRUE;                                             // Set error code for no error
}


/**********************************************************************************************
 * Function:        uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, \
 *                                                           uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 *
 * Pre-Condition:   Do not use if powering Sabertooth from batteries, only needed for use with
 *                      power supplies
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    If you change this from the default value of 30 Volts, you can not set it
 *                      for more than 25 Volts. In order to reset it to a higher value, you must
 *                      use the DEScribe software available from Dimension Engineering
 * Overview:        Checks command for validity, and passes it to the serial port
 * Notes:           This function is valid for Sabertooth Command 3
 *********************************************************************************************/

uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, uint8_t address ) {

    uint8_t new_max_voltage = DEFAULT_MAXIMUM_VOLTAGE;

    if ( desired_maximum_voltage < MIN_MAXIMUM_VOLTAGE ||  \
         desired_maximum_voltage > MAX_MAXIMUM_VOLTAGE ) {

            new_max_voltage = DEFAULT_MAXIMUM_VOLTAGE;
        return FALSE;                                       // Set error code for error
    }

    else {
        new_max_voltage = desired_maximum_voltage;
    }

    send_command ( SET_MAX_VOLTAGE, new_max_voltage, address );
    return TRUE;                                            // Set error code for no error
}


/**********************************************************************************************
 * Function:        uint8_t set_serial_timeout ( uint8_t desired_timeout_period, \
 *                                               uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    None
 * Overview:        Checks command for validity, and passes it to the serial port
 *                  Value received by the Sabertooth is in multiples of 100 milli-seconds
 *                      EXAMPLE: '1' = 100 ms
 *                  I set the max timeout value at a discretionary value of 5 seconds; you can
 *                      set it as desired by changing the "MAX_SERIAL_TIMEOUT" constant #define,
 *                      in the header file under "Command Data"
 * Notes:           This function is valid for Sabertooth Command 14
 *********************************************************************************************/

uint8_t set_serial_timeout ( uint8_t desired_timeout_period, uint8_t address ) {

    uint8_t new_timeout_period = DEFAULT_SERIAL_TIMEOUT;

    if ( desired_timeout_period < MIN_SERIAL_TIMEOUT || \
         desired_timeout_period > MAX_SERIAL_TIMEOUT ) {

            new_timeout_period = DEFAULT_SERIAL_TIMEOUT;
        return FALSE;                                       // Set error code for error
    }

    else {
        new_timeout_period = desired_timeout_period;
    }

   send_command ( SET_SERIAL_TIMEOUT, new_timeout_period, address );
   return TRUE;                                             // Set error code for no error
}


/**********************************************************************************************
 * Function:        uint8_t set_baudrate ( uint8_t desired_baudrate, \
 *                                         uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    None
 * Overview:        Checks command for validity, and passes it to the serial port
 *                  set_baudrate accepts baud values between 2,400 and 38,400 (commands 1-4),
 *                      with a default value of 9,600 baud (command 2)
 * Notes:           This function is valid for Sabertooth Command 15
 *********************************************************************************************/

uint8_t set_baudrate ( uint8_t desired_baudrate, uint8_t address ) {

    static uint8_t new_baudrate = DEFAULT_BAUDRATE;

    if ( desired_baudrate < BAUDRATE_2400 || \
         desired_baudrate > BAUDRATE_38400 ) {

            new_baudrate = DEFAULT_BAUDRATE;
            return FALSE;                                   // Set error code for error
    }

    else {
        new_baudrate = desired_baudrate;
    }

    send_command ( SET_BAUD_RATE, new_baudrate, address );
    return TRUE;                                            // Set error code for no error
}


/**********************************************************************************************
 * Function:        uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, \
 *                                             uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    None
 * Overview:        Checks command for validity, and passes it to the serial port
 *                  set_ramping_rate accepts the desired ramping rate, which must be a value between
 *                      zero and eighty ( 0 - 80 )
 * Notes:           This function is valid for Sabertooth Command 16
 *********************************************************************************************/

uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, uint8_t address ) {

    static uint8_t new_ramping_rate = DEFAULT_RAMPING_VALUE;

    if ( desired_ramping_rate < MIN_RAMPING_VALUE || \
         desired_ramping_rate > MAX_RAMPING_VALUE ) {

            new_ramping_rate = DEFAULT_RAMPING_VALUE;
        return FALSE;                                       // Set error code for error
    }

    else {
        new_ramping_rate = desired_ramping_rate;
    }

    send_command ( SET_RAMPING_RATE, new_ramping_rate, address );
    return TRUE;                                            // Set error code for no error
}


/**********************************************************************************************
 * Function:        uint8_t set_deadband_range ( uint8_t desired_deadband, \
 *                                               uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
 * Pre-Condition:   None
 * Input:           Receives command data from the application program
 * Output:          Sends the command to the send_command function,
 *                      and then to the serial port; returns true or false to calling function, to
 *                      verify valid commands received and processed
 * Side Effects:    None
 * Overview:        Checks command for validity, and passes it to the serial port
 *                  set_deadband_range accepts the desired deadband, which must be a value
 *                      between zero and 127
 *                  Value is set as follows:
 *                      ( 127 - command value ) < motors_off < ( 128 + command value )
 * Notes:           This function is valid for Sabertooth Command 17
 *********************************************************************************************/

uint8_t set_deadband_range ( uint8_t desired_deadband, uint8_t address ) {

    static uint8_t new_deadband = DEFAULT_DEADBAND;

    if ( desired_deadband < MIN_DEADBAND || desired_deadband > MAX_DEADBAND ) {

         new_deadband = DEFAULT_DEADBAND;
         return FALSE;                                      // Set error code for error
    }

    else {
        new_deadband = desired_deadband;
    }

    send_command ( SET_DEADBAND, new_deadband, address );
    return TRUE;                                            // Set error code for no error
}



/**********************************************************************************************
 * Function:        static void send_command ( uint8_t command, uint8_t value, uint8_t address )
 *
 * Pre-Condition:   None
 * Input:           Receives the command data from the driver functions
 * Output:          Sends the three commands plus their checksum to the serial port, and through
 *                      that to the Sabertooth Motor Controller
 * Side Effects:    None
 * Overview:        None
 * Notes:           Static helper function, for use only by driver functions in this file
 *********************************************************************************************/

    /* Helper Command, for internal driver use only
     * Defining it here, in the .c file, instead of in the .h file, to prevent
     * compiler warning about it being declared "static", but never defined
     * This is correct, since it is not for the user, only the user's functions */

    static void send_command ( uint8_t command, uint8_t value, uint8_t address );

/*********************************************************************************************/
static void send_command ( uint8_t command, uint8_t value, uint8_t address ) {
    assert  ( command < COMMAND_HIGH_LIMIT);
    putchar ( address );
    putchar ( command );
    putchar ( value );
    putchar ( ( address + command + value ) & CRC_MASK );
}





/**********************************************************************************************
 * END OF SABERTOOTH 2x25 DRIVER
 *********************************************************************************************/



Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library 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