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.*/voidpaddleInit(void){// The handpaddle is connected to UART port #0 (pin 10)// Set serial rateUBRR0H = (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 interruptsUCSR0C = _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;}elsepLabel = &&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;}elsepLabel = &&wait_for_sync;return;/* Get the mystery fourth byte*/get_dec_sync:if (b8 != 0){pLabel = &&get_dec_direction;}elsepLabel = &&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;}elsepLabel = &&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 syncpLabel = &&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;#endifif (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();}}