#!/bin/bash
# =================================================================
# Bushnell Northstar / Meade Autostar Telescope Control Script
# =================================================================
# Controls a telescope via serial port using Arrow Keys and Number Keys.
# Protocol: Meade LX200 / Autostar Generic
#
# CONTROLS:
# Arrow Keys : Start moving (North/South/East/West)
# Spacebar : STOP Moving (Important!)
# 1-9 : Set Speed (1=Slowest/Guide, 9=Fastest/Slew)
# q : Quit the program
# =================================================================
# Default Serial Port (can be changed by user input)
SERIAL_PORT="/dev/ttyS0"
# Function to monitor raw data for debugging
debug_raw_monitor() {
local port="$1"
echo ""
echo "====================================================="
echo " RAW DATA MONITOR (Debug Mode)"
echo "====================================================="
echo " Monitoring port: $port"
echo " Settings: 9600 baud, 8N1, Raw, No Flow Control"
echo "-----------------------------------------------------"
echo " Sending test command (:GR#) every 2 seconds..."
echo " Incoming data will be shown as HEXADECIMAL values."
echo " - 0000 : Null bytes (line noise)"
echo " - 3a47 5223 : Valid ASCII text"
echo "-----------------------------------------------------"
echo " Press Ctrl+C to Stop Monitoring and Exit."
echo "====================================================="
# Configure port explicitly
# Added -crtscts (no hardware flow control) and -hupcl (no hangup/DTR reset)
stty -F "$port" 9600 cs8 -cstopb -parenb raw -echo -crtscts clocal -hupcl
# Start a background loop to ping the telescope so we provoke a response
# We use a subshell to keep it contained
(
while true; do
echo -ne ":GR#" > "$port" 2>/dev/null
sleep 2
done
) &
BG_PID=$!
# Ensure we kill the background pinger when this function/script stops
trap "kill $BG_PID 2>/dev/null; exit" INT TERM EXIT
# Listen to the port and dump hex
# We use 'od -x' (octal dump -hex) to see exactly what bytes come in
od -x < "$port"
}
# Function to attempt to auto-detect the telescope
scan_ports() {
echo "Scanning ports for telescope response (sending :GR#)..."
FOUND_PORT=""
# Check common serial device patterns
for port in /dev/ttyUSB* /dev/ttyS[0-9]; do
# Check if port exists
if [ -e "$port" ]; then
# Try 9600 baud first (Standard Meade)
# Added clocal -crtscts -hupcl to prevent telescope resets
if stty -F "$port" 9600 cs8 -cstopb -parenb raw -echo -crtscts clocal -hupcl 2>/dev/null; then
# Clear any existing data in buffer
timeout 0.2s cat "$port" >/dev/null 2>&1
# Send "Get RA" command
echo -ne ":GR#" > "$port" 2>/dev/null
# Try to read response
RESPONSE=$(timeout 1s head -c 10 "$port" 2>/dev/null | tr -d '\0')
if [[ "$RESPONSE" == *"#"* ]] || [[ "$RESPONSE" =~ [0-9] ]]; then
echo " [FOUND] Telescope detected on $port (Response: $RESPONSE)"
FOUND_PORT="$port"
else
echo " [ ... ] Checked $port (9600) - No valid response"
fi
fi
# If not found, try 19200 baud (Some Northstar clones use this)
if [ -z "$FOUND_PORT" ]; then
stty -F "$port" 19200 cs8 -cstopb -parenb raw -echo -crtscts clocal -hupcl 2>/dev/null
timeout 0.2s cat "$port" >/dev/null 2>&1
echo -ne ":GR#" > "$port" 2>/dev/null
RESPONSE=$(timeout 1s head -c 10 "$port" 2>/dev/null | tr -d '\0')
if [[ "$RESPONSE" == *"#"* ]] || [[ "$RESPONSE" =~ [0-9] ]]; then
echo " [FOUND] Telescope detected on $port (19200 baud) (Response: $RESPONSE)"
FOUND_PORT="$port"
# Reconfigure main script variable if found at different baud
stty -F "$port" 19200 cs8 -cstopb -parenb raw -echo -crtscts clocal -hupcl 2>/dev/null
fi
fi
fi
done
if [ ! -z "$FOUND_PORT" ]; then
echo ""
echo "Auto-selected likely port: $FOUND_PORT"
SERIAL_PORT="$FOUND_PORT"
else
echo "Scan complete. No obvious telescope response found."
# Fallback Monitor Prompt
echo ""
echo "(!) Connection Troubleshooting:"
echo " If the telescope RESETS when scanned, the DTR line is likely active."
echo " This script now attempts to disable DTR (-hupcl)."
read -p " Start Raw Data Monitor to debug? (y/n): " RUN_DEBUG
if [[ "$RUN_DEBUG" =~ ^[Yy]$ ]]; then
# Ask which port to monitor since we didn't find one
echo ""
echo "Available Ports:"
ls /dev/ttyS* /dev/ttyUSB* 2>/dev/null
read -p "Enter Port to Monitor [default: /dev/ttyS0]: " DEBUG_PORT
if [ -z "$DEBUG_PORT" ]; then DEBUG_PORT="/dev/ttyS0"; fi
if [ -e "$DEBUG_PORT" ]; then
debug_raw_monitor "$DEBUG_PORT"
exit 0 # Exit script after monitoring
else
echo "Error: Port $DEBUG_PORT does not exist."
exit 1
fi
fi
fi
}
# -----------------------------------------------------------------
# 1. Setup Serial Port
# -----------------------------------------------------------------
echo "-----------------------------------------------------"
echo " Telescope Control Interface (Bash)"
echo "-----------------------------------------------------"
# Run the scan function
scan_ports
echo "-----------------------------------------------------"
echo "Available Serial Ports:"
ls /dev/ttyS* /dev/ttyUSB* 2>/dev/null
echo ""
read -p "Enter Serial Port [default: $SERIAL_PORT]: " USER_PORT
if [ ! -z "$USER_PORT" ]; then
SERIAL_PORT="$USER_PORT"
fi
if [ ! -e "$SERIAL_PORT" ]; then
echo "Error: Port $SERIAL_PORT does not exist."
exit 1
fi
# Configure the serial port using stty
# Added clocal -crtscts -hupcl to prevent resets
stty -F "$SERIAL_PORT" 9600 cs8 -cstopb -parenb raw -echo -crtscts clocal -hupcl
echo "Connected to $SERIAL_PORT at 9600 baud."
echo "Initializing..."
# Send a Stop command just in case
echo -ne ":Q#" > "$SERIAL_PORT"
# -----------------------------------------------------------------
# 2. Control Loop
# -----------------------------------------------------------------
CURRENT_SPEED="Max"
print_ui() {
clear
echo "====================================================="
echo " TELESCOPE CONTROL PANEL"
echo "====================================================="
echo " Port: $SERIAL_PORT | Status: Ready"
echo "-----------------------------------------------------"
echo " [ UP ] Move North"
echo " [DOWN] Move South"
echo " [LEFT] Move West"
echo " [RGHT] Move East"
echo " [SPACE] STOP ALL MOTORS"
echo "-----------------------------------------------------"
echo " Current Speed Setting: $CURRENT_SPEED"
echo " [1-2] Guide (Slowest/Nudge)"
echo " [3-5] Center (Slow)"
echo " [6-8] Find (Medium)"
echo " [9] Slew (Max Speed)"
echo "-----------------------------------------------------"
echo " Press 'q' to Quit Script"
echo "====================================================="
}
print_ui
# Loop to capture keystrokes one by one
while true; do
# Read 1 character silently (-s), 3 chars if it's an escape sequence
read -rsn1 key
# If key is empty (sometimes happens), skip
if [[ -z "$key" ]]; then continue; fi
# Handle Escape Sequences (Arrow Keys start with ESC)
if [[ "$key" == $'\x1b' ]]; then
read -rsn2 key # Read the next 2 characters
case "$key" in
'[A') # UP Arrow
echo -ne ":Mn#" > "$SERIAL_PORT"
;;
'[B') # DOWN Arrow
echo -ne ":Ms#" > "$SERIAL_PORT"
;;
'[D') # LEFT Arrow
echo -ne ":Mw#" > "$SERIAL_PORT"
;;
'[C') # RIGHT Arrow
echo -ne ":Me#" > "$SERIAL_PORT"
;;
esac
else
# Handle Standard Keys
case "$key" in
# SPACEBAR - The most important key! Stops the telescope.
' ')
echo -ne ":Q#" > "$SERIAL_PORT"
;;
# Speed Controls (Mapped to Meade Standard Rate Commands)
'1'|'2')
# Guide Rate (Very Slow / Nudge)
echo -ne ":RG#" > "$SERIAL_PORT"
CURRENT_SPEED="Guide (Slowest)"
print_ui
;;
'3'|'4'|'5')
# Center Rate (Slow)
echo -ne ":RC#" > "$SERIAL_PORT"
CURRENT_SPEED="Center (Slow)"
print_ui
;;
'6'|'7'|'8')
# Find Rate (Medium)
echo -ne ":RM#" > "$SERIAL_PORT"
CURRENT_SPEED="Find (Medium)"
print_ui
;;
'9')
# Slew Rate (Fastest)
echo -ne ":RS#" > "$SERIAL_PORT"
CURRENT_SPEED="Slew (Max)"
print_ui
;;
# Quit Application
'q')
echo "Stopping telescope..."
echo -ne ":Q#" > "$SERIAL_PORT"
exit 0
;;
esac
fi
done