Subversion Repositories svnkaklik

Rev

Blame | Last modification | View Log | Download

/* 
 * Copyright (C) 2004 Darren Hutchinson (dbh@gbdt.com.au)
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Library General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA. 
 *
 * $Id: serial.c,v 1.10 2004/04/04 10:32:50 dbh Exp $
 */

#include <inttypes.h>
#include <avr/io.h>

#include "eq6.h"
#include "serial.h"
#include "combine.h"
#include "stepper.h"
#include "paddle.h"
#include "sr.h"

/* This file accepts serial data from a serial guider and performs the
 * requested guiding operation.
 *
 * This interface is also is designed to support future mount management
 * operations via the same serial interface
 *
 * The current protocol is:
 *
 * [0-9]    Add the number to the "accumulator"
 * -        Denote accumulator as negative
 * #        Clear the accumulator and flag
 * <        Clear the flag
 * >        Set the flag
 * U        Copy flag state to the DEC UP key
 * D        Copy flag state to the DEC DOWN key
 * L        Copy flag state to the RA left key
 * R        Copy flag state to the RA right key
 * C        Release all keys
 *
 * B        Set DEC backlash to accum
 * M        Set DEC backlash mode (+ = finish pos, 0 = none, - = finish neg)
 * b        Set RA backlash to accum
 * m        Set RA backlash mode (see DEC backlash)
 *
 * G        Set 2X paddle to guiding speed (0.3x) if flag set, 1X if clear
 *
 * t        Use halfStep for slow step if flag set, microStep if clear (TEST)
 *
 * T        Set the tracking rate as-per the accumulator
 *          -1 = No tracking (Terrestial)
 *          0 = Sidereal
 *          1 = Solar / Planetary
 *          2 = Lunar
 *
 * g        Set transmission (gearbox) ratio
 *
 * The '#' and accumulator support future value-based entries
 *
 * A subset of LX200 commands are supported for compatibility
 * with various autoguiding programs.
 *
 * :Me# :Mw# :Ms# :Mn#          Start slewing East(right), West(left),
 *                              North (up), South (down)
 * :Qe# :Qw# :Qs# :Qn# :Q#      Halt selected or all slews
 * :RG# :RC# :RM# :RS#          Set guiding rate for LX200 motions
 *                              G = 0.3x
 *                              C = 1x
 *                              M = 8x
 *                              S = 16x
 *                                      
 * ACK                          Returns alignment mode (always 'P' polar)
 */
#include <avr/interrupt.h>
#include <inttypes.h>

#include "paddle.h"
#include "eq6.h"
#include "combine.h"

/* serialInit() initializes the serial port used for the 
 * serial guider input.
 *
 * Passed:
 *         Nothing
 *
 * Returns:
 *         Nothing.
 */
void
serialInit(void)
{
    // The serial guider is attached to USART1

    // Set serial rate
    UBRR1H = (CLK_RATE / GUIDE_BAUD / 16 - 1) >> 8;
    UBRR1L = (CLK_RATE / GUIDE_BAUD / 16 - 1) & 0xff;

    /* Setup registers
     * 8 bits, no parity, RX enable, TX enable. Only the Rx interrupts are
     * enabled at this point.
     */
    UCSR1B = 0;            // Disable all interrupts
    UCSR1C = _BV(URSEL1) | _BV(UCSZ11) | _BV(UCSZ10);
    UCSR1B = _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1);
}

/* serialInt() is called whenever a character is received on USART1.
 * These characters are send by the serial guider
 *
 * Passed:
 *         Nothing
 *
 * Returns:
 *         Nothing
 *
 * Notes:
 *         Interrupts are disabled during processing
 */
SIGNAL(SIG_USART1_RECV)
{
    /* Variables for flags/accumulator */
    static uint8_t      flag = 0;
    static uint16_t     accum = 0;
    static uint8_t      sign = 0;

    /* Variable holding current guiding rate */
    static int8_t       guideRate = SPEED_0_33_X;

    /* Flags holding current requested slewing directions */
    static uint8_t      upFlag;
    static uint8_t      downFlag;
    static uint8_t      leftFlag;
    static uint8_t      rightFlag;

    /* LX200 command state */
#define LX200_CMD_LEN   8
    static char         lxCmd[LX200_CMD_LEN];
    static uint8_t      lxPos;

    uint8_t             ch;
    uint8_t             dirChg;

    static uint8_t      lxMode;


    /* Get the character from the port. This will dismiss the interrupt
     */
    dirChg = 0;
    ch = UDR1;
    /* UDR1 = ch;       /* Echo for debugging */

    /* This code processes commands when a LX200 command is not currently
     * being processed.
     */
    if (lxMode == 0)
    {
        switch(ch)
        {
        case '0' ... '9':
            /* Add it to the accumulator */
            accum = (accum * 10) + ch - '0';
            break;

        case '#':
            /* Clear the accumulator */
            accum = 0;
            sign = 0;
            break;

        case '-':
            /* Set the sign of the accumulator to negative */
            sign = 1;
            break;

        case '<':
            /* Clear the flag */
            flag = 0;
            break;

        case '>':
            /* Set the flag */
            flag = 1;
            break;

        case 'U':
            /* Guide UP (DEC) */
            upFlag = flag;
            dirChg = 1;
            break;

        case 'D':
            /* Guide DOWN (DEC) */
            downFlag = flag;
            dirChg = 1;
            break;

        case 'R':
            /* Guide RIGHT (RA) */
            rightFlag = flag;
            dirChg = 1;
            break;

        case 'L':
            /* Guide LEFT (RA) */
            leftFlag = flag;
            dirChg = 1;
            break;

        case 'C':
            /* Clear all keys */
            upFlag = downFlag = leftFlag = rightFlag = 0;
            dirChg = 1;
            break;

        case 'b':
            /* Set RA backlash steps */
            raState.backlash = accum;
            doSave = 1;
            break;

        case 'B':
            /* Set DEC backlash steps */
            decState.backlash = accum;
            doSave = 1;
            break;

        case 'm':
            /* Set RA backlash mode */
            raState.finNeg = raState.finPos = 0;
            if (accum != 0)
            {
                if (sign)
                    raState.finNeg = 1;
                else
                    raState.finPos = 1;
            }
            doSave = 1;
            break;

        case 'M':
            /* Set DEC backlash mode */
            decState.finNeg = decState.finPos = 0;
            if (accum != 0)
            {
                if (sign)
                    decState.finNeg = 1;
                else
                    decState.finPos = 1;
            }
            doSave = 1;
            break;

        case 'G':
            /* Set the speed for the 2x paddle button. This has
             * no effect on the rate used for serial commands
             */
            paddleGuideRate = flag ? SPEED_0_33_X : SPEED_1_X;
            doSave = 1;
            break;

        case 'T':
            /* Set the tracking speed */
            setTrackRate(sign ? -accum : accum);
            doSave = 1;
            break;

        case 'g':       /* Set transmission (gearbox) ratio */
            transRatio = accum;
            doSave = 1;
            break;

        case 't':
            /* *TEST* Allow half step table to be specified instead of
             * the microstep table
             */
            doHalfStep = flag;
            break;

        case '\006':        /* LX200: ACK */
            UDR1 = 'P';
            break;

        case ':':           /* LX200: Start command */
            /* This indicates the start of a LX200 command */
            lxMode = 1;
            lxPos = 0;
            break;

        default:
            /* OK, now we're confused .... */
            UDR1 = '?';
            break;
        }
    }
    else
    {
        /* This section of code supports the LX200 commands. They
         * have a fundimentally different syntax to the existing
         * commands, so they are implemented in this code seperately
         * for clarity.
         */
        if (ch != '#')
        {
            /* Add this to the command characters so far */
            lxCmd[lxPos++] = ch;
            if (lxPos == LX200_CMD_LEN)
            {
                /* Too much data for any command */
                UDR1 = '?';
                lxMode = 0;
            }
        }
        else
        {
            /* We are going back to native mode after this */
            lxMode = 0;

            if (lxPos >= 1)
            {
                /* We have a complete LX200 command (without the delimiters).
                 * Do what it asks
                 */
                switch(lxCmd[0])
                {
                case 'M':       // Start guiding in specified direction
                    if (lxPos == 2)
                    {
                        // We have the right number of chars */
                        switch (lxCmd[1])
                        {
                        case 'n': upFlag = 1; break;
                        case 's': downFlag = 1; break;
                        case 'e': rightFlag = 1; break;
                        case 'w': leftFlag = 1; break;
                        default: UDR1 = '?'; break;
                        }

                        dirChg = 1;
                    }
                    break;

                case 'Q':       // Stop guiding in specified direction
                    if (lxPos == 1)
                    {
                        // Stop slewing
                        upFlag = downFlag = leftFlag = rightFlag = 0;
                        dirChg = 1;
                    }
                    else if (lxPos == 2)
                    {
                        // Stop slewing is specified direction
                        switch (lxCmd[1])
                        {
                        case 'n': upFlag = 0; break;
                        case 's': downFlag = 0; break;
                        case 'e': rightFlag = 0; break;
                        case 'w': leftFlag = 0; break;
                        default: UDR1 = '?'; break;
                        }

                        dirChg = 1;
                    } else
                        UDR1 = '?';
                    break;

                case 'R':           // Set guiding speed
                    if (lxPos == 2)
                    {
                        switch (lxCmd[1])
                        {
                        case 'G':   guideRate = SPEED_0_33_X; break;
                        case 'C':   guideRate = SPEED_1_X; break;
                        case 'M':   guideRate = SPEED_8_X; break;
                        case 'S':   guideRate = SPEED_16_X; break;
                        default: UDR1 = '?'; break;
                        }
                        dirChg = 1;
                    }
                    break;
                default:
                    UDR1 = '?';
                }
            }
        }
    }

    /* Update the serial guiding rate data if it has changed */
    if (dirChg)
    {
        if (upFlag)
            rateInput.serialDecRate = guideRate;
        else if (downFlag)
            rateInput.serialDecRate = -guideRate;
        else
            rateInput.serialDecRate = SPEED_0_X;

        if (rightFlag)
            rateInput.serialRaRate = guideRate;
        else if (leftFlag)
            rateInput.serialRaRate = -guideRate;
        else
            rateInput.serialRaRate = SPEED_0_X;
    }
    updateMountSpeed();
}