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();
}
}