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: paddle.c,v 1.4 2004/03/03 07:37:11 dbh Exp $
 */

/* This file handles the interface to the EQ-6/Atlas hand paddle.
 *
 * This paddle generates a continuous serial stream containing information
 * about the state of the paddle. Unlike many simple paddles the EQ-6 has a
 * small microprocessor to handle the various functions (debouncing, switch
 * refersal, etc)
 *
 * See the file eq6-serial.txt for further information on the prototcol
 * used by the hand paddle.
 */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

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

uint8_t  paddleGuideRate = SPEED_1_X;

/* paddleInit() initializes the serial port used for the EQ6/Atlas
 * hand paddle. The communication with this port is only in one
 * direction (from paddle to mount).
 *
 * Passed:
 *         Nothing
 *
 * Returns:
 *         Nothing.
 */
void
paddleInit(void)
{
    // The handpaddle is connected to UART port #0 (pin 10)

    // Set serial rate
    UBRR0H = (CLK_RATE / PADDLE_RATE / 16 - 1) >> 8;
    UBRR0L = (CLK_RATE / PADDLE_RATE / 16 - 1) & 0xff;

    /* Setup registers
     * 9 bits, RX enable
     */
    UCSR0B = 0;            // Disable all interrupts
    UCSR0C = _BV(URSEL0) | _BV(UCSZ01) | _BV(UCSZ00);
    UCSR0B = _BV(RXCIE0) | _BV(UCSZ02) | _BV(RXEN0);
}

/* paddleInt() is called whenever a character is received on USART0.
 * These characters are send by the hand paddle
 *
 * Passed:
 *         Nothing
 *
 * Returns:
 *         Nothing
 *
 * Notes:
 *         This function inplemented a state machine to properly
 *         synchronize with the incoming character stream.
 *
 *         Interrupts are disabled during processing
 */
SIGNAL(SIG_USART0_RECV)
{
    uint8_t             lowerByte;
    uint8_t             b8;

    static void         *pLabel = &&wait_for_sync;

    static uint8_t      raDir = 0;
    static uint8_t      raSpeed = 0;
    static uint8_t      decDir = 0;

    static uint8_t      oldRaDir = (uint8_t)-1;
    static uint8_t      oldRaSpeed = (uint8_t)-1;
    static uint8_t      oldDecDir = (uint8_t)-1;
    static uint8_t      oldDecSpeed = (uint8_t)-1;

    /* Read the nine bits of transferred data. We don't do this
     * during initialization as the order is important!
     */
    b8 = UCSR0B & _BV(RXB80);
    lowerByte = UDR0;

    /* Jump to the code that handles the current reception system. Note that
     * this feature is GCC specific.
     */
    goto *pLabel;

    /* Wait for the RA sync byte
     */
wait_for_sync:
    if ((b8 == 0) && (lowerByte == RA_SYNC))
        pLabel = &&get_ra_direction;
    return;

    /* Get the RA direction - this will have b8 == 0
     */
get_ra_direction:
    if (b8 == 0)
    {
        raDir = lowerByte & _BV(RA_DIR_BIT);
        pLabel = &&get_ra_speed;
    }
    else
        pLabel = &&wait_for_sync;
    return;

    /* Get the RA speed - this will have b8 == 0
     */
get_ra_speed:
    if (b8 == 0)
    {
        raSpeed = lowerByte & RA_SPEED_MASK;
        pLabel = &&get_dec_sync;
    }
    else
        pLabel = &&wait_for_sync;
    return;

    /* Get the mystery fourth byte
     */
get_dec_sync:
    if (b8 != 0)
    {
        pLabel = &&get_dec_direction;
    }
    else
        pLabel = &&wait_for_sync;
    return;

    /* Get the DEC direction - this will have b8 != 0
     */
get_dec_direction:
    if (b8 != 0)
    {
        decDir = lowerByte & _BV(DEC_DIR_BIT);
        pLabel = &&get_dec_speed;
    }
    else
        pLabel = &&wait_for_sync;
    return;

    /* Get the RA speed - this will have b8 == 0
     */
get_dec_speed:
    // We've got all the words - the next state will always be wait for sync
    pLabel = &&wait_for_sync;
    lowerByte &= DEC_SPEED_MASK;

    /* If the parity is correct and any of the bytes are different then
     * process them
     */
    if (    b8 != 0
            && (        (oldRaDir != raDir) 
                        || (oldRaSpeed != raSpeed) 
                        || (oldDecDir != decDir) 
                        || (oldDecSpeed != lowerByte)))
    {
        /* Update "old" indications */
        oldRaDir = raDir;
        oldRaSpeed = raSpeed;
        oldDecDir = decDir;
        oldDecSpeed = lowerByte;
            
        /* Process the data from the paddle
         * - if the RA speed is one then setup the siderial speed
         * - convert the RA speed/direction into a device independent form
         * - convert the DEC speed/direction into a device independent form
         */
        if (raSpeed == RA_SPEED_0)
        {
            rateInput.paddleRaRate = -paddleGuideRate;
            
            /* This is a little trick because the "direction" bit doesn't
             * work then the speed is zero. Do a pre-invert if the
             * siderial rate is for the northern hemisphere
             */
            if (rateInput.siderialRate == SPEED_SIDERIAL)
                rateInput.paddleRaRate = -rateInput.paddleRaRate;
        }
        else if (raSpeed == RA_SPEED_1)
        {
            rateInput.paddleRaRate = SPEED_0_X;
            rateInput.siderialRate = raDir ? SPEED_SIDERIAL : -SPEED_SIDERIAL;
        }
        else if (raSpeed == RA_SPEED_2)
            rateInput.paddleRaRate = paddleGuideRate;
        else if (raSpeed == RA_SPEED_8)
            rateInput.paddleRaRate = SPEED_8_X;
        else if (raSpeed == RA_SPEED_16)
            rateInput.paddleRaRate = SPEED_16_X;

#if 0
        /* The direction of the RA keys is reversed when operating in
         * the southern hemisphere, so modify them back
         */
        if ((raDir == 0) ^ (rateInput.siderialRate == SPEED_SIDERIAL))
             rateInput.paddleRaRate = -rateInput.paddleRaRate;
#else
        /* Use the keys as returned by the paddle. These are reversed when
         * operating in the southern hemisphere. This ensures that the
         * "right" key always increases the RA angle
         */
        if (raDir == 0)
             rateInput.paddleRaRate = -rateInput.paddleRaRate;
#endif

        if (lowerByte == DEC_SPEED_0)
            rateInput.paddleDecRate = SPEED_0_X;
        else if (lowerByte == DEC_SPEED_2)
            rateInput.paddleDecRate = paddleGuideRate;
        else if (lowerByte == DEC_SPEED_8)
            rateInput.paddleDecRate = SPEED_8_X;
        else if (lowerByte == DEC_SPEED_16)
            rateInput.paddleDecRate = SPEED_16_X;

        if (decDir != 0)
            rateInput.paddleDecRate = -rateInput.paddleDecRate;

        /* Ok, all parsed. Force an update of the combined speed
         */
        updateMountSpeed();
    }
}