diff --git a/.gitignore b/.gitignore index ee090794..289afbcf 100644 --- a/.gitignore +++ b/.gitignore @@ -366,3 +366,5 @@ Software/Arduino code/OpenAstroTracker/__vm test bin/ +Software/Arduino code/HW_724_TEST +Software/Arduino code/sketch_jun08a diff --git a/Software/Arduino code/OpenAstroTracker/DayTime.cpp b/Software/Arduino code/OpenAstroTracker/DayTime.cpp index 8e870a52..821557a4 100644 --- a/Software/Arduino code/OpenAstroTracker/DayTime.cpp +++ b/Software/Arduino code/OpenAstroTracker/DayTime.cpp @@ -67,7 +67,7 @@ float DayTime::getTotalSeconds() const { return 3600.0f * getHours() + (float)getMinutes() * 60.0f + (float)getSeconds(); } -int DayTime::getTime(int& h, int& m, int& s) const { +void DayTime::getTime(int& h, int& m, int& s) const { h = hours; m = mins; s = secs; @@ -228,16 +228,12 @@ float DegreeTime::getTotalDegrees() const { void DegreeTime::checkHours() { if (hours > 0) { -#ifdef DEBUG_MODE - logv("CheckHours: Degrees is more than 0, clamping"); -#endif + LOGV1(DEBUG_GENERAL, "CheckHours: Degrees is more than 0, clamping"); hours = 0; } if (hours < -180) { -#ifdef DEBUG_MODE - logv("CheckHours: Degrees is less than -180, clamping"); -#endif - hours = -180; + LOGV1(DEBUG_GENERAL, "CheckHours: Degrees is less than -180, clamping"); + hours = -180; } } diff --git a/Software/Arduino code/OpenAstroTracker/DayTime.hpp b/Software/Arduino code/OpenAstroTracker/DayTime.hpp index f50ca6b8..ef26d2b0 100644 --- a/Software/Arduino code/OpenAstroTracker/DayTime.hpp +++ b/Software/Arduino code/OpenAstroTracker/DayTime.hpp @@ -33,7 +33,7 @@ class DayTime { float getTotalMinutes() const; float getTotalSeconds() const; - int getTime(int& h, int& m, int& s) const; + void getTime(int& h, int& m, int& s) const; void set(int h, int m, int s); void set(const DayTime& other); diff --git a/Software/Arduino code/OpenAstroTracker/EPROMStore.cpp b/Software/Arduino code/OpenAstroTracker/EPROMStore.cpp new file mode 100644 index 00000000..8d7dff22 --- /dev/null +++ b/Software/Arduino code/OpenAstroTracker/EPROMStore.cpp @@ -0,0 +1,75 @@ +#include +#include "EPROMStore.hpp" +#include "Utility.hpp" + +// The global instance of the platform-independant EEPROM class +EPROMStore *EPROMStore::_eepromStore = NULL; + +// Initialize the EEPROM storage in a platform-independent abstraction +void EPROMStore::initialize() +{ + LOGV2(DEBUG_VERBOSE, "EEPROM: Initialize. Instance is %s", _eepromStore == NULL ? "NULL" : "VALID"); + if (_eepromStore == NULL) + { + LOGV1(DEBUG_VERBOSE, "EEPROM: Creating single instance"); + _eepromStore = new EPROMStore(); + } +} + +// Get the instance of the EEPROM storage +EPROMStore *EPROMStore::Storage() +{ + return _eepromStore; +} + +#ifdef ESPBOARD + +// Construct the EEPROM object for ESP boards, settign aside 32 bytes for storage +EPROMStore::EPROMStore() +{ + LOGV1(DEBUG_VERBOSE, "EEPROM[ESP]: Startup with 32 bytes"); + EEPROM.begin(32); +} + +// Update the given location with the given value +void EPROMStore::update(int location, uint8_t value) +{ + LOGV3(DEBUG_VERBOSE, "EEPROM[ESP]: Writing %x to %d", value, location); + EEPROM.write(location, value); + LOGV1(DEBUG_VERBOSE, "EEPROM[ESP]: Committing"); + EEPROM.commit(); +} + +// Read the value at the given location +uint8_t EPROMStore::read(int location) +{ + uint8_t value; + value = EEPROM.read(location); + LOGV3(DEBUG_VERBOSE, "EEPROM[ESP]: Read %x from %d", value, location); + return value; +} + +#else + +// Construct the EEPROM object for non-ESP boards +EPROMStore::EPROMStore() +{ + LOGV1(DEBUG_VERBOSE, "EEPROM[UNO]: Startup "); +} + +// Update the given location with the given value +void EPROMStore::update(int location, uint8_t value) +{ + LOGV3(DEBUG_VERBOSE, "EEPROM[UNO]: Writing %x to %d", value, location); + EEPROM.write(location, value); +} + +// Read the value at the given location +uint8_t EPROMStore::read(int location) +{ + uint8_t value = EEPROM.read(location); + LOGV3(DEBUG_VERBOSE, "EEPROM[UNO]: Read %x from %d", value, location); + return value; +} + +#endif diff --git a/Software/Arduino code/OpenAstroTracker/EPROMStore.hpp b/Software/Arduino code/OpenAstroTracker/EPROMStore.hpp new file mode 100644 index 00000000..d54c672a --- /dev/null +++ b/Software/Arduino code/OpenAstroTracker/EPROMStore.hpp @@ -0,0 +1,18 @@ +#pragma once +#include + +// Platform independant abstraction of the EEPROM storage capability of the boards. +// This is needed because the ESP boards require two things that the Arduino boards don't: +// 1) It wants to know how many bytes you want to use (at most) +// 2) It wants you to call a commit() function after a write() to actual persist the data. +class EPROMStore { + static EPROMStore *_eepromStore; +public: + EPROMStore(); + static void initialize(); + + void update(int location, uint8_t value); + uint8_t read(int location); + static EPROMStore* Storage(); +}; + diff --git a/Software/Arduino code/OpenAstroTracker/Globals.cpp b/Software/Arduino code/OpenAstroTracker/Globals.cpp index f2af18a6..aafcd074 100644 --- a/Software/Arduino code/OpenAstroTracker/Globals.cpp +++ b/Software/Arduino code/OpenAstroTracker/Globals.cpp @@ -1,10 +1,2 @@ #include "Globals.hpp" -#include - -void EEPROMupdate(int loc, byte val) -{ - if (EEPROM.read(loc)!=val) - { - EEPROM.write(loc,val); - } -} +#include "Utility.hpp" diff --git a/Software/Arduino code/OpenAstroTracker/Globals.hpp b/Software/Arduino code/OpenAstroTracker/Globals.hpp index 3f5ad57f..f0fe3b03 100644 --- a/Software/Arduino code/OpenAstroTracker/Globals.hpp +++ b/Software/Arduino code/OpenAstroTracker/Globals.hpp @@ -4,8 +4,6 @@ #include #include -void EEPROMupdate(int loc, byte val); - // Set to 1 if you are in the northern hemisphere. #define NORTHERN_HEMISPHERE 1 @@ -19,88 +17,126 @@ void EEPROMupdate(int loc, byte val); // Make some variables in the sketch files available to the C++ code. extern bool inSerialControl; extern String version; -extern int PolarisRAHour; -extern int PolarisRAMinute; -extern int PolarisRASecond; -// Comment this out to save some code space -// #define DEBUG_MODE -#ifdef DEBUG_MODE - // #define SEND_PERIODIC_UPDATES -#endif -// Uncomment to run a key diagnostic. No tracker functions are on at all. -// #define LCD_BUTTON_TEST +extern byte PolarisRAHour; +extern byte PolarisRAMinute; +extern byte PolarisRASecond; + +// Debugging output control +// Each bit in the debug level specifies a kind of debug to enable. +#define DEBUG_NONE 0x00 +#define DEBUG_INFO 0x01 +#define DEBUG_SERIAL 0x02 +#define DEBUG_WIFI 0x04 +#define DEBUG_MOUNT 0x08 +#define DEBUG_MOUNT_VERBOSE 0x10 +#define DEBUG_GENERAL 0x20 +#define DEBUG_MEADE 0x40 +#define DEBUG_VERBOSE 0x80 +#define DEBUG_ANY 0xFF + +// Bit Name Output +// 0 DEBUG_INFO General output, like startup variables and status +// 1 DEBUG_SERIAL Serial commands and replies +// 2 DEBUG_WIFI Wifi related output +// 3 DEBUG_MOUNT Mount processing output +// 4 DEBUG_MOUNT_VERBOSE Verbose mount processing (coordinates, etc) +// 5 DEBUG_GENERAL Other misc. output +// 6 DEBUG_MEADE Meade command handling output + +// Set this to specify the amount of debug output OAT should send to the serial port. +// Note that if you use an app to control OAT, ANY debug output will likely confuse that app. +// Debug output is useful if you are using Wifi to control the OAT or if you are issuing +// manual commands via a terminal. +// +// #define DEBUG_LEVEL (DEBUG_SERIAL|DEBUG_WIFI|DEBUG_INFO|DEBUG_MOUNT|DEBUG_GENERAL) +// #define DEBUG_LEVEL (DEBUG_ANY) +// #define DEBUG_LEVEL (DEBUG_INFO|DEBUG_MOUNT|DEBUG_GENERAL) +#define DEBUG_LEVEL (DEBUG_NONE) -// Uncomment to reverse the direction of RA motor -// #define INVERT_RA_DIR +// Set this to 1 to run a key diagnostic. No tracker functions are on at all. +#define LCD_BUTTON_TEST 0 -// Uncomment to reverse the direction of DEC motor -// #define INVERT_DEC_DIR +// Set to 1 to reverse the direction of RA motor +#define INVERT_RA_DIR 0 -//////////////////////////////////////////////////////////////// -// -// FEATURE SUPPORT SECTION -// -// Since the Arduino Uno has very little memory (32KB code, 2KB data) all features -// stretch the Uno a little too far. So in order to save memory we allow you to enable -// and disable features to help manage memory usage. -// If you run the tracker with an Arduino Mega, you can uncomment all the features. -// -// If you would like to drive your OAT mount with only the LCD Shield, -// you should comment out SUPPORT_SERIAL_CONTROL -// -// If you feel comfortable with configuring the OAT at startup manually, you should comment -// out SUPPORT_GUIDED_STARTUP (maybe after you've used it for a while you know what to do). -// -// The POI menu can take a little data memory and you may not need it. If not, you can comment -// out SUPPORT_POINTS_OF_INTEREST -// -//////////////////////////////////////////////////////////////// +// Set to 1 to reverse the direction of DEC motor +#define INVERT_DEC_DIR 0 -// If you do not have a LCD shield on your Arduino Uno, uncomment the line below. This is +// If you do not have a LCD shield on your Arduino Uno, set this to 1 on the line below. This is // useful if you are always going to run the mount from a laptop anyway. -// #define HEADLESS_CLIENT +#define HEADLESS_CLIENT 0 + +// This is set to 1 for boards that do not support interrupt timers +#define RUN_STEPPERS_IN_MAIN_LOOP 0 -#ifdef ESP8266 - #define HEADLESS_CLIENT +#if defined(ESP8266) || defined(ESP32) + #define ESPBOARD + #undef HEADLESS_CLIENT + #define HEADLESS_CLIENT 1 #define WIFI_ENABLED - #define INFRA_SSID "yourSSID" - #define INFRA_WPAKEY "yourWPAKey" + #define INFRA_SSID "YouSSID" + #define INFRA_WPAKEY "YourWPAKey" #define OAT_WPAKEY "superSecret" #define HOSTNAME "OATerScope" // 0 - Infrastructure Only - Connecting to a Router // 1 - AP Mode Only - Acting as a Router // 2 - Attempt Infrastructure, Fail over to AP Mode. #define WIFI_MODE 2 + #if defined(ESP8266) + #undef RUN_STEPPERS_IN_MAIN_LOOP + #define RUN_STEPPERS_IN_MAIN_LOOP 1 + #endif #endif -// Uncomment this to enable the heating menu +//////////////////////////////////////////////////////////////// +// +// FEATURE SUPPORT SECTION +// +// Since the Arduino Uno has very little memory (32KB code, 2KB data) all features +// stretch the Uno a little too far. So in order to save memory we allow you to enable +// and disable features to help manage memory usage. +// If you run the tracker with an Arduino Mega, you can set all the features to 1. +// +// If you would like to drive your OAT mount with only the LCD Shield, or are on a Uno, +// you should set SUPPORT_SERIAL_CONTROL to 0 +// +// If you feel comfortable with configuring the OAT at startup manually, you should set +// SUPPORT_GUIDED_STARTUP to 0 (maybe after you've used it for a while you know what to do). +// +// The POI menu can take a little data memory and you may not need it. If not, you can set +// SUPPORT_POINTS_OF_INTEREST to 0 +// +//////////////////////////////////////////////////////////////// + +// Set this to 1 this to enable the heating menu // NOTE: Heating is currently not supported! -// #define SUPPORT_HEATING +#define SUPPORT_HEATING 0 + +#if HEADLESS_CLIENT == 0 -#ifndef HEADLESS_CLIENT + // Set this to 1 to support Guided Startup + #define SUPPORT_GUIDED_STARTUP 1 - // Uncomment to support Guided Startup - #define SUPPORT_GUIDED_STARTUP + // Set this to 1 to support full GO (was POI) menu. + // If this is set to 0 you still have a GO menu that has Home and Park. + #define SUPPORT_POINTS_OF_INTEREST 1 - // Uncomment to support full GO (was POI) menu. - // If this is commented out you still have a GO menu that has Home and Park. - #define SUPPORT_POINTS_OF_INTEREST + // Set this to 1 to support CTRL menu, allowing you to manually slew the mount with the buttons. + #define SUPPORT_MANUAL_CONTROL 1 - // Uncomment to support CTRL menu, allowing you to manually slew the mount with the buttons. - #define SUPPORT_MANUAL_CONTROL + // Set this to 1 to support CAL menu, allowing you to calibrate various things + #define SUPPORT_CALIBRATION 1 - // Uncomment to support CAL menu, allowing you to calibrate various things - #define SUPPORT_CALIBRATION + // Set this to 1 to support INFO menu that displays various pieces of information about the mount. + #define SUPPORT_INFO_DISPLAY 1 - // Uncomment to support INFO menu that displays various pieces of information about the mount. - // #define SUPPORT_INFO_DISPLAY + // Set this to 1 to support Serial Meade LX200 protocol support + #define SUPPORT_SERIAL_CONTROL 1 - // Uncomment to support Serial Meade LX200 protocol support - // #define SUPPORT_SERIAL_CONTROL #else // If we are making a headleass (no screen, no keyboard) client, always enable Serial. - #define SUPPORT_SERIAL_CONTROL -#endif + #define SUPPORT_SERIAL_CONTROL 1 +#endif // HEADLESS_CLIENT -#endif +#endif // _GLOBALS_HPP diff --git a/Software/Arduino code/OpenAstroTracker/InterruptCallback.cpp b/Software/Arduino code/OpenAstroTracker/InterruptCallback.cpp index 7bcfa6df..0b968c3e 100644 --- a/Software/Arduino code/OpenAstroTracker/InterruptCallback.cpp +++ b/Software/Arduino code/OpenAstroTracker/InterruptCallback.cpp @@ -9,6 +9,8 @@ // NOTE: ESP8266 support is not complete and does not work. This code is never called. #ifdef ESP8266 #include "ESP8266TimerInterrupt.h" +#elif defined ESP32 + // We don't support ESP32 boards in interrupt mode #elif defined __AVR_ATmega328P__ || defined __AVR_ATmega2560__ // Arduino Uno or Mega #define USE_TIMER_1 true #define USE_TIMER_2 true @@ -17,9 +19,7 @@ #define USE_TIMER_5 false #include "TimerInterrupt.h" #else - // Need to add support for ESP32 boards here - - #error Only Arduino Uno, Mega and ESP8266 boards currently supported. + #error Unrecognized board selected. Either implement interrupt code or define the board here. #endif #ifdef ESP8266 @@ -46,6 +46,8 @@ bool InterruptCallback::setInterval(float intervalMs, interrupt_callback_p callb // This timer library requires microsecond interval definitions interruptHandler.setInterval(1000.0f * intervalMs, esp8266callback); + + return true; } void InterruptCallback::start() @@ -56,8 +58,56 @@ void InterruptCallback::stop() { } -#else +#elif defined(ESP32) + +/* +volatile bool _lock = false; + +void IRAM_ATTR callbackProxy() { + if (_lock) { + return; + } + + timerAlarmDisable(_timer); + _lock = true; + if (func != NULL) { + func(data); + } + _lock = false; + timerAlarmEnable(_timer); +} + +bool InterruptCallback::setInterval(float intervalMs, interrupt_callback_p callback, void* payload){ + func = callback; + data = payload; + + // 80 divisor = 1uS resolution. + _timer = timerBegin(0, 80, true); + timerAttachInterrupt(_timer, callbackProxy, true); + timerAlarmWrite(_timer, (uint64_t)(intervalMs * 1000.0f), true); + timerAlarmEnable(_timer); + + LOGV1(DEBUG_INFO, "Setup ESP32 Timer"); + + return true; +} + +void InterruptCallback::stop(){ + LOGV1(DEBUG_INFO, "Stop ESP32 Timer"); + if (timerAlarmEnabled(_timer)) { + timerAlarmDisable(_timer); + } +} + +void InterruptCallback::start(){ + LOGV1(DEBUG_INFO, "Start ESP32 Timer"); + if (!timerAlarmEnabled(_timer)){ + timerAlarmEnable(_timer); + } +} +*/ +#elif defined __AVR_ATmega328P__ || defined __AVR_ATmega2560__ bool InterruptCallback::setInterval(float intervalMs, interrupt_callback_p callback, void* payload) { diff --git a/Software/Arduino code/OpenAstroTracker/InterruptCallback.hpp b/Software/Arduino code/OpenAstroTracker/InterruptCallback.hpp index 7e44515d..9a2e3d37 100644 --- a/Software/Arduino code/OpenAstroTracker/InterruptCallback.hpp +++ b/Software/Arduino code/OpenAstroTracker/InterruptCallback.hpp @@ -1,4 +1,5 @@ #pragma once + #include "Globals.hpp" ////////////////////////////////////// diff --git a/Software/Arduino code/OpenAstroTracker/LcdMenu.cpp b/Software/Arduino code/OpenAstroTracker/LcdMenu.cpp index 57e8dfe0..a41276f7 100644 --- a/Software/Arduino code/OpenAstroTracker/LcdMenu.cpp +++ b/Software/Arduino code/OpenAstroTracker/LcdMenu.cpp @@ -1,7 +1,8 @@ #include "Utility.hpp" +#include "EPROMStore.hpp" #include "LcdMenu.hpp" -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 // Class that drives the LCD screen with a menu // You add a string and an id item and this class handles the display and navigation @@ -17,7 +18,12 @@ LcdMenu::LcdMenu(byte cols, byte rows, int maxItems) : _lcd(8, 9, 4, 5, 6, 7) { _activeCol = -1; _lastDisplay[0] = ""; _lastDisplay[1] = ""; - _menuItems = new MenuItem * [maxItems]; + _menuItems = new MenuItem * [maxItems]; + + _brightness = EPROMStore::Storage()->read(11); + LOGV2(DEBUG_INFO, "LCD: Brightness from EEPROM is %d", _brightness); + // pinMode(10, OUTPUT); + // analogWrite(10, _brightness); // Create special characters for degrees and arrows _lcd.createChar(_degrees, DegreesBitmap); @@ -71,6 +77,26 @@ void LcdMenu::clear() { _lcd.clear(); } +// Set the brightness of the backlight +void LcdMenu::setBacklightBrightness(int level, bool persist) { + _brightness = level; + + LOGV2(DEBUG_INFO, "LCD: Writing %d as brightness", _brightness ); + + // analogWrite(10, _brightness); + + LOGV2(DEBUG_INFO, "LCD: Wrote %d as brightness", _brightness ); + if (persist) { + LOGV2(DEBUG_INFO, "LCD: Saving %d as brightness", (_brightness & 0x00FF)); + EPROMStore::Storage()->update(11, (byte)(_brightness & 0x00FF)); + } +} + +// Get the current brightness +int LcdMenu::getBacklightBrightness() { + return _brightness; +} + // Go to the next menu item from currently active one void LcdMenu::setNextActive() { @@ -126,7 +152,7 @@ void LcdMenu::updateDisplay() { } // Display the actual menu string - while ((pBufMenu < bufMenu + _columns) && (offsetIntoString < menuString.length())) { + while ((pBufMenu < bufMenu + _columns) && (offsetIntoString < (int)menuString.length())) { *(pBufMenu++) = menuString[offsetIntoString++]; } @@ -173,7 +199,7 @@ void LcdMenu::printMenu(String line) { _lcd.setCursor(_activeCol, _activeRow); int spaces = _columns - line.length(); - for (int i = 0; i < line.length(); i++) { + for (unsigned int i = 0; i < line.length(); i++) { printChar(line[i]); } @@ -282,3 +308,50 @@ void LcdMenu::printMenu(String line) {} void LcdMenu::printChar(char ch) {} #endif + +/* +class SubMenu { + + display() { } + onUp() { } + onDown() { } + + } +} + +class Menu { + List subMenu + int activeSubIndex=0 + UseContinuousKeys(UP|DOWN|LEFT|RIGHT) + + virtual OnUp() { previousSubmenu } + virtual OnDown() { nextSubmenu } + virtual OnRight() { nextmenu } + virtual OnLeft() { nextItemInSubmenu } + virtual OnSelect() { confirm } + + displayMenu() { } + + run(){ + if (any continuous keys) + { + if + } + } +} + +class MenuSystem { + List menus; + + run() { + if (!activeMenu->run()) + { + activeMenu++ + } + } +} + +Menu RA ; +RA.fnDisplay = [] { _lcdMenu.goto(0,1); _lcdMenu.printMenu(_mount.targetRA()); } +RA.fnUp() = [] { } +*/ diff --git a/Software/Arduino code/OpenAstroTracker/LcdMenu.hpp b/Software/Arduino code/OpenAstroTracker/LcdMenu.hpp index b6dfa805..2dd9b6e1 100644 --- a/Software/Arduino code/OpenAstroTracker/LcdMenu.hpp +++ b/Software/Arduino code/OpenAstroTracker/LcdMenu.hpp @@ -2,7 +2,7 @@ #define _LCDMENU_HPP_ #include -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 #include #endif #include "Globals.hpp" @@ -50,6 +50,10 @@ class LcdMenu { // Pass thru utility function void setCursor(byte col, byte row); + // Set and get the brightness of the backlight + void setBacklightBrightness(int level, bool persist = true); + int getBacklightBrightness(); + // Pass thru utility function void clear(); @@ -69,7 +73,7 @@ class LcdMenu { void printChar(char ch); private: -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 LiquidCrystal _lcd; // The LCD screen that we'll display the menu on MenuItem** _menuItems; // The first menu item (linked list) byte _numMenuItems; @@ -79,6 +83,7 @@ class LcdMenu { byte _activeRow; // The row that the LCD cursor is on byte _activeCol; // The column that the LCD cursor is on String _lastDisplay[2]; // The last string that was displayed on each row + int _brightness; byte _degrees = 1; byte _minutes = 2; diff --git a/Software/Arduino code/OpenAstroTracker/MeadeCommandProcessor.cpp b/Software/Arduino code/OpenAstroTracker/MeadeCommandProcessor.cpp index c444b14e..5ae88352 100644 --- a/Software/Arduino code/OpenAstroTracker/MeadeCommandProcessor.cpp +++ b/Software/Arduino code/OpenAstroTracker/MeadeCommandProcessor.cpp @@ -364,7 +364,7 @@ MeadeCommandProcessor* MeadeCommandProcessor::instance() { MeadeCommandProcessor::MeadeCommandProcessor(Mount* mount, LcdMenu* lcdMenu) { _mount = mount; - // In HEADLESS_CLIENT, the lcdMenu is just an empty shell class to save having to null check everywhere + // In HEADLESS_CLIENT mode, the lcdMenu is just an empty shell class to save having to null check everywhere _lcdMenu = lcdMenu; } @@ -474,9 +474,7 @@ String MeadeCommandProcessor::handleMeadeSetInfo(String inCmd) { deg = -90 - deg; } _mount->targetDEC().set(deg, inCmd.substring(5, 7).toInt(), inCmd.substring(8, 10).toInt()); -#ifdef DEBUG_MODE - logv("MeadeSetInfo: Received Target DEC: %s", _mount->targetDEC().ToString()); -#endif + LOGV2(DEBUG_MEADE, "MEADE: SetInfo: Received Target DEC: %s", _mount->targetDEC().ToString()); return "1"; } else { @@ -492,9 +490,7 @@ String MeadeCommandProcessor::handleMeadeSetInfo(String inCmd) { if ((inCmd[3] == ':') && (inCmd[6] == ':')) { _mount->targetRA().set(inCmd.substring(1, 3).toInt(), inCmd.substring(4, 6).toInt(), inCmd.substring(7, 9).toInt()); -#ifdef DEBUG_MODE - logv("MeadeSetInfo: Received Target RA: %s", _mount->targetRA().ToString()); -#endif + LOGV2(DEBUG_MEADE, "MEADE: SetInfo: Received Target RA: %s", _mount->targetRA().ToString()); return "1"; } else { @@ -513,9 +509,7 @@ String MeadeCommandProcessor::handleMeadeSetInfo(String inCmd) { } DayTime lst(hLST, minLST, secLST); -#ifdef DEBUG_MODE - logv("MeadeSetInfo: Received LST: %d:%d:%d", hLST, minLST, secLST); -#endif + LOGV4(DEBUG_MEADE, "MEADE: SetInfo: Received LST: %d:%d:%d", hLST, minLST, secLST); _mount->setLST(lst); } else if (inCmd[1] == 'P') { @@ -527,9 +521,7 @@ String MeadeCommandProcessor::handleMeadeSetInfo(String inCmd) { // Set HA int hHA = inCmd.substring(1, 3).toInt(); int minHA = inCmd.substring(4, 6).toInt(); -#ifdef DEBUG_MODE - logv("MeadeSetInfo: Received HA: %d:%d:%d", hHA, minHA, 0); -#endif + LOGV4(DEBUG_MEADE, "MEADE: SetInfo: Received HA: %d:%d:%d", hHA, minHA, 0); _mount->setHA(DayTime(hHA, minHA, 0)); } @@ -794,11 +786,11 @@ String MeadeCommandProcessor::handleMeadeQuit(String inCmd) { // Set Slew Rates ///////////////////////////// String MeadeCommandProcessor::handleMeadeSetSlewRate(String inCmd) { - switch (inCmd[1]) { - case 'S': // Slew - Fastest - case 'M': // Find - 2nd Fastest - case 'C': // Center - 2nd Slowest - case 'G': // Guide - Slowest + switch (inCmd[0]) { + case 'S': _mount->setSlewRate(4); break; // Slew - Fastest + case 'M': _mount->setSlewRate(3); break; // Find - 2nd Fastest + case 'C': _mount->setSlewRate(2); break; // Center - 2nd Slowest + case 'G': _mount->setSlewRate(1); break; // Guide - Slowest default: break; } @@ -806,7 +798,8 @@ String MeadeCommandProcessor::handleMeadeSetSlewRate(String inCmd) { } String MeadeCommandProcessor::processCommand(String inCmd) { - if (inCmd[0] = ':') { + if (inCmd[0] == ':') { + LOGV2(DEBUG_MEADE, "MEADE: Received command '%s'", inCmd.c_str()); char command = inCmd[1]; inCmd = inCmd.substring(2); switch (command) { @@ -820,11 +813,9 @@ String MeadeCommandProcessor::processCommand(String inCmd) { case 'R': return handleMeadeSetSlewRate(inCmd); case 'X': return handleMeadeExtraCommands(inCmd); default: -#ifdef DEBUG_MODE - Serial.println("Unknown Command in MeadeCommandProcessor::processCommand " + inCmd); - return ""; -#endif + LOGV2(DEBUG_MEADE, "MEADE: Received unknown command '%s'", inCmd.c_str()); break; } } + return ""; } diff --git a/Software/Arduino code/OpenAstroTracker/Mount.cpp b/Software/Arduino code/OpenAstroTracker/Mount.cpp index 1764ef92..f987ccd6 100644 --- a/Software/Arduino code/OpenAstroTracker/Mount.cpp +++ b/Software/Arduino code/OpenAstroTracker/Mount.cpp @@ -1,10 +1,9 @@ -#include - #include "InterruptCallback.hpp" #include "LcdMenu.hpp" #include "Mount.hpp" #include "Utility.hpp" +#include "EPROMStore.hpp" //mountstatus #define STATUS_PARKED 0B0000000000000000 @@ -36,7 +35,7 @@ #define SLEW_MASK_WEST B1000 #define SLEW_MASK_ANY B1111 -char* formatStringsDEC[] = { +const char* formatStringsDEC[] = { "", " %c%02d@ %02d' %02d\"", // LCD Menu w/ cursor "%c%02d*%02d'%02d#", // Meade @@ -45,7 +44,7 @@ char* formatStringsDEC[] = { "%c%02d%02d%02d", // Compact }; -char* formatStringsRA[] = { +const char* formatStringsRA[] = { "", " %02dh %02dm %02ds", // LCD Menu w/ cursor "%02d:%02d:%02d#", // Meade @@ -78,6 +77,7 @@ Mount::Mount(int stepsPerRADegree, int stepsPerDECDegree, LcdMenu* lcdMenu) { _stepperWasRunning = false; _totalDECMove = 0; _totalRAMove = 0; + _moveRate = 4; #if RA_Stepper_TYPE == 0 _backlashCorrectionSteps = 16; #else @@ -95,18 +95,28 @@ Mount::Mount(int stepsPerRADegree, int stepsPerDECDegree, LcdMenu* lcdMenu) { ///////////////////////////////// void Mount::startTimerInterrupts() { -#ifndef ESP8266 +#ifndef ESPBOARD // 2 kHz updates - if (!InterruptCallback::setInterval(0.5f, mountLoop, this)) + if (!InterruptCallback::setInterval(1.0f, mountLoop, this)) { -#ifdef DEBUG_MODE - logv("CANNOT set Timer!"); -#endif + LOGV1(DEBUG_MOUNT, "Mount:: CANNOT setup interrupt timer!"); } -#endif // !ESP8266 -} +#endif // !ESPBOARD +} +///////////////////////////////// +// +// readConfiguration +// +///////////////////////////////// +void Mount::readConfiguration() +{ + LOGV1(DEBUG_INFO, "Mount: Reading configuration data from EEPROM"); + readPersistentData(); + LOGV1(DEBUG_INFO, "Mount: Done reading configuration data from EEPROM"); +} + ///////////////////////////////// // // readPersistentData @@ -125,39 +135,44 @@ void Mount::startTimerInterrupts() void Mount::readPersistentData() { // Read the magic marker byte and state - int marker = EEPROM.read(4) + EEPROM.read(5) * 256; -#ifdef DEBUG_MODE - logv("EEPROM: Marker: %x ", marker); -#endif + uint8_t markerLo=EPROMStore::Storage()->read(4); + uint8_t markerHi=EPROMStore::Storage()->read(5); + + uint16_t marker = (uint16_t)markerLo + (uint16_t)markerHi * 256; + LOGV4(DEBUG_INFO, "Mount: EEPROM: Marker: %x (L:%d H:%d)", marker, markerLo, markerHi); if ((marker & 0xFF01) == 0xBE01) { - _stepsPerRADegree = EEPROM.read(6) + EEPROM.read(7) * 256; -#ifdef DEBUG_MODE - logv("EEPROM: RA Marker OK! RA steps/deg is %d", _stepsPerRADegree); -#endif + _stepsPerRADegree = EPROMStore::Storage()->read(6) + EPROMStore::Storage()->read(7) * 256; + LOGV2(DEBUG_INFO,"Mount: EEPROM: RA Marker OK! RA steps/deg is %d", _stepsPerRADegree); + } + else{ + LOGV1(DEBUG_INFO,"Mount: EEPROM: No stored value for RA steps"); } if ((marker & 0xFF02) == 0xBE02) { - _stepsPerDECDegree = EEPROM.read(8) + EEPROM.read(9) * 256; -#ifdef DEBUG_MODE - logv("EEPROM: DEC Marker OK! DEC steps/deg is %d", _stepsPerDECDegree); -#endif + _stepsPerDECDegree = EPROMStore::Storage()->read(8) + EPROMStore::Storage()->read(9) * 256; + LOGV2(DEBUG_INFO,"Mount: EEPROM: DEC Marker OK! DEC steps/deg is %d", _stepsPerDECDegree); + } + else{ + LOGV1(DEBUG_INFO,"Mount: EEPROM: No stored value for DEC steps"); } float speed = 1.0; if ((marker & 0xFF04) == 0xBE04) { - int adjust = EEPROM.read(0) + EEPROM.read(3) * 256; + int adjust = EPROMStore::Storage()->read(0) + EPROMStore::Storage()->read(3) * 256; speed = 1.0 + 1.0 * adjust / 10000.0; -#ifdef DEBUG_MODE - logv("EEPROM: Speed Marker OK! Speed adjust is %d, speedFactor is %f", adjust, speed); -#endif + LOGV3(DEBUG_INFO,"Mount: EEPROM: Speed Marker OK! Speed adjust is %d, speedFactor is %f", adjust, speed); + } + else{ + LOGV1(DEBUG_INFO,"Mount: EEPROM: No stored value for speed factor"); } if ((marker & 0xFF08) == 0xBE08) { - _backlashCorrectionSteps = EEPROM.read(10) + EEPROM.read(11) * 256; -#ifdef DEBUG_MODE - logv("EEPROM: Backlash Steps Marker OK! Backlash correction is %d", _backlashCorrectionSteps); -#endif + _backlashCorrectionSteps = EPROMStore::Storage()->read(10) + EPROMStore::Storage()->read(11) * 256; + LOGV2(DEBUG_INFO,"Mount: EEPROM: Backlash Steps Marker OK! Backlash correction is %d", _backlashCorrectionSteps); + } + else{ + LOGV1(DEBUG_INFO,"Mount: EEPROM: No stored value for backlash correction"); } setSpeedCalibration(speed, false); @@ -170,17 +185,17 @@ void Mount::readPersistentData() ///////////////////////////////// void Mount::writePersistentData(int which, int val) { - int flag = 0x00; + uint8_t flag = 0x00; int loByteLocation = 0; int hiByteLocation = 0; // If we're written something before... - if (EEPROM.read(5) == 0xBE) { + uint8_t magicMarker = EPROMStore::Storage()->read(5); + LOGV4(DEBUG_INFO,"Mount: EEPROM Write: Marker is %x, flag is %x (%d)", magicMarker, flag, flag); + if (magicMarker == 0xBE) { // ... read the current state ... - flag = EEPROM.read(4); -#ifdef DEBUG_MODE - logv("EEPROM Write: Marker is 0xBE, flag is %x (%d)", flag, flag); -#endif + flag = EPROMStore::Storage()->read(4); + LOGV3(DEBUG_INFO,"Mount: EEPROM Write: Marker is 0xBE, flag is %x (%d)", flag, flag); } switch (which) { case RA_STEPS: @@ -189,6 +204,7 @@ void Mount::writePersistentData(int which, int val) flag |= 0x01; loByteLocation = 6; hiByteLocation = 7; + LOGV2(DEBUG_INFO,"Mount: EEPROM Write: Updating RA steps to %d", val); } break; case DEC_STEPS: @@ -197,6 +213,7 @@ void Mount::writePersistentData(int which, int val) flag |= 0x02; loByteLocation = 8; hiByteLocation = 9; + LOGV2(DEBUG_INFO,"Mount: EEPROM Write: Updating DEC steps to %d", val); } break; case SPEED_FACTOR_DECIMALS: @@ -205,6 +222,7 @@ void Mount::writePersistentData(int which, int val) flag |= 0x04; loByteLocation = 0; hiByteLocation = 3; + LOGV2(DEBUG_INFO,"Mount: EEPROM Write: Updating Speed factor to %d", val); } break; case BACKLASH_CORRECTION: @@ -213,19 +231,20 @@ void Mount::writePersistentData(int which, int val) flag |= 0x08; loByteLocation = 10; hiByteLocation = 11; + LOGV2(DEBUG_INFO,"Mount: EEPROM Write: Updating Backlash to %d", val); } break; } -#ifdef DEBUG_MODE - logv("EEPROM Write: New Marker is 0xBE, flag is %x (%d)", flag, flag); -#endif + LOGV3(DEBUG_INFO,"Mount: EEPROM Write: New Marker is 0xBE, flag is %x (%d)", flag, flag); + + EPROMStore::Storage()->update(4, flag); + EPROMStore::Storage()->update(5, 0xBE); - EEPROMupdate(4, flag); - EEPROMupdate(5, 0xBE); + EPROMStore::Storage()->update(loByteLocation, val & 0x00FF); + EPROMStore::Storage()->update(hiByteLocation, (val >> 8) & 0x00FF); - EEPROMupdate(loByteLocation, val & 0x00FF); - EEPROMupdate(hiByteLocation, (val >> 8) & 0x00FF); + LOGV5(DEBUG_INFO,"Mount: EEPROM Write: Wrote %x to %d and %x to %d", val & 0x00FF, loByteLocation, (val >> 8) & 0x00FF, hiByteLocation); } ///////////////////////////////// @@ -303,6 +322,7 @@ void Mount::configureDECStepper(byte stepMode, byte pin1, byte pin2, int maxSpee _maxDECAcceleration = maxAcceleration; } #endif + ///////////////////////////////// // // getSpeedCalibration @@ -318,12 +338,17 @@ float Mount::getSpeedCalibration() { // ///////////////////////////////// void Mount::setSpeedCalibration(float val, bool saveToStorage) { + LOGV3(DEBUG_MOUNT, "Mount: Updating speed calibration from %f to %f", _trackingSpeedCalibration , val); _trackingSpeedCalibration = val; + LOGV2(DEBUG_MOUNT, "Mount: Current tracking speed is %f steps/sec", _trackingSpeed); + // The tracker simply needs to rotate at 15degrees/hour, adjusted for sidereal // time (i.e. the 15degrees is per 23h56m04s. 86164s/86400 = 0.99726852. 3590/3600 is the same ratio) So we only go 15 x 0.99726852 in an hour. _trackingSpeed = _trackingSpeedCalibration * _stepsPerRADegree * siderealDegreesInHour / 3600.0f; + LOGV2(DEBUG_MOUNT, "Mount: New tracking speed is %f steps/sec", _trackingSpeed); + if (saveToStorage) { val = (val - 1.0) * 10000; if (val > 32766) val = 32766; @@ -350,6 +375,8 @@ int Mount::getStepsPerDegree(int which) if (which == DEC_STEPS) { return _stepsPerDECDegree; } + + return 0; } ///////////////////////////////// @@ -394,15 +421,28 @@ void Mount::setBacklashCorrection(int steps) { writePersistentData(BACKLASH_CORRECTION, steps); } +///////////////////////////////// +// +// setHA +// +///////////////////////////////// +void Mount::setSlewRate(int rate) +{ + _moveRate = clamp(rate, 1, 4); + float speedFactor[] = { 0, 0.05, 0.2, 0.5, 1.0}; + LOGV3(DEBUG_MOUNT,"Mount::setSlewRate: rate is %d -> %f",_moveRate , speedFactor[_moveRate ]); + _stepperDEC->setMaxSpeed(speedFactor[_moveRate ] * _maxDECSpeed); + _stepperRA->setMaxSpeed(speedFactor[_moveRate ] * _maxRASpeed); + LOGV3(DEBUG_MOUNT,"Mount::setSlewRate: new speeds are RA: %f DEC: %f",_stepperRA->maxSpeed(), _stepperDEC->maxSpeed()); +} + ///////////////////////////////// // // setHA // ///////////////////////////////// void Mount::setHA(const DayTime& haTime) { -#ifdef DEBUG_MODE - logv("setHA: HA: %s", haTime.ToString()); -#endif + LOGV2(DEBUG_MOUNT,"Mount: setHA: HA is %s", haTime.ToString()); DayTime lst = DayTime(PolarisRAHour, PolarisRAMinute, PolarisRASecond); lst.addTime(haTime); setLST(lst); @@ -415,18 +455,12 @@ void Mount::setHA(const DayTime& haTime) { // ///////////////////////////////// const DayTime Mount::HA() const { -#ifdef DEBUG_MODE - logv("Mount: Get HA."); - logv("Mount: Polaris adjust: %s", DayTime(PolarisRAHour, PolarisRAMinute, PolarisRASecond).ToString()); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"Mount: Get HA."); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount: Polaris adjust: %s", DayTime(PolarisRAHour, PolarisRAMinute, PolarisRASecond).ToString()); DayTime ha = _LST; -#ifdef DEBUG_MODE - logv("Mount: LST: %s", _LST.ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount: LST: %s", _LST.ToString()); ha.subtractTime(DayTime(PolarisRAHour, PolarisRAMinute, PolarisRASecond)); -#ifdef DEBUG_MODE - logv("Mount: LST-Polaris is HA: %s", ha.ToString()); -#endif + LOGV2(DEBUG_MOUNT,"Mount: GetHA: LST-Polaris is HA %s", ha.ToString()); return ha; } @@ -447,9 +481,7 @@ const DayTime& Mount::LST() const { void Mount::setLST(const DayTime& lst) { _LST = lst; _zeroPosRA = lst; -#ifdef DEBUG_MODE - logv("Mount: LST and ZeroPosRA set to: %s", _LST.ToString()); -#endif + LOGV2(DEBUG_MOUNT,"Mount: Set LST and ZeroPosRA to: %s", _LST.ToString()); } ///////////////////////////////// @@ -516,16 +548,12 @@ const DayTime Mount::currentRA() const { // How many steps moves the RA ring one sidereal hour along. One sidereal hour moves just shy of 15 degrees float stepsPerSiderealHour = _stepsPerRADegree * siderealDegreesInHour; float hourPos = 2.0 * -_stepperRA->currentPosition() / stepsPerSiderealHour; -#ifdef DEBUG_MODE - logv("CurrentRA: Steps/h : %s (%d x %s)", String(stepsPerSiderealHour, 2).c_str(), _stepsPerRADegree, String(siderealDegreesInHour, 5).c_str()); - logv("CurrentRA: RA Steps : %d", _stepperRA->currentPosition()); - logv("CurrentRA: POS : %s", String(hourPos).c_str()); -#endif + LOGV4(DEBUG_MOUNT_VERBOSE,"CurrentRA: Steps/h : %s (%d x %s)", String(stepsPerSiderealHour, 2).c_str(), _stepsPerRADegree, String(siderealDegreesInHour, 5).c_str()); + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: RA Steps : %d", _stepperRA->currentPosition()); + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: POS : %s", String(hourPos).c_str()); hourPos += _zeroPosRA.getTotalHours(); -#ifdef DEBUG_MODE - logv("CurrentRA: ZeroPos : %s", _zeroPosRA.ToString()); - logv("CurrentRA: POS (+zp) : %s", DayTime(hourPos).ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: ZeroPos : %s", _zeroPosRA.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: POS (+zp) : %s", DayTime(hourPos).ToString()); bool flipRA = NORTHERN_HEMISPHERE ? _stepperDEC->currentPosition() < 0 @@ -534,14 +562,10 @@ const DayTime Mount::currentRA() const { { hourPos += 12; if (hourPos > 24) hourPos -= 24; -#ifdef DEBUG_MODE - logv("CurrentRA: RA (+12h): %s", DayTime(hourPos).ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: RA (+12h): %s", DayTime(hourPos).ToString()); } -#ifdef DEBUG_MODE - logv("CurrentRA: RA Pos -> : %s", DayTime(hourPos).ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentRA: RA Pos -> : %s", DayTime(hourPos).ToString()); return hourPos; } @@ -554,23 +578,17 @@ const DayTime Mount::currentRA() const { const DegreeTime Mount::currentDEC() const { float degreePos = 1.0 * _stepperDEC->currentPosition() / _stepsPerDECDegree; -#ifdef DEBUG_MODE - logv("CurrentDEC: Steps/deg : %d", _stepsPerDECDegree); - logv("CurrentDEC: DEC Steps : %d", _stepperDEC->currentPosition()); - logv("CurrentDEC: POS : %s", String(degreePos).c_str()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentDEC: Steps/deg : %d", _stepsPerDECDegree); + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentDEC: DEC Steps : %d", _stepperDEC->currentPosition()); + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentDEC: POS : %s", String(degreePos).c_str()); if (degreePos > 0) { degreePos = -degreePos; -#ifdef DEBUG_MODE - logv("CurrentDEC: Greater Zero, flipping."); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"CurrentDEC: Greater Zero, flipping."); } -#ifdef DEBUG_MODE - logv("CurrentDEC: POS : %s", DegreeTime(degreePos).ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"CurrentDEC: POS : %s", DegreeTime(degreePos).ToString()); return degreePos; } @@ -579,16 +597,17 @@ const DegreeTime Mount::currentDEC() const { // syncPosition // ///////////////////////////////// -// Set the current RA and DEC position to be the given coordinate. We do this by settign the stepper motor coordinate +// Set the current RA and DEC position to be the given coordinate. We do this by setting the stepper motor coordinate // to be at the calculated positions (that they would be if we were slewing there). void Mount::syncPosition(int raHour, int raMinute, int raSecond, int decDegree, int decMinute, int decSecond) { - // Given the display RA coordinates... - DayTime newRA = DayTime(raHour, raMinute, raSecond); - DayTime newDEC = DayTime(decDegree, decMinute, decSecond); + _targetRA.set(raHour,raMinute,raSecond); + _targetDEC.set(decDegree,decMinute,decSecond); float targetRA, targetDEC; + LOGV7(DEBUG_MOUNT, "Mount: Sync Position to RA: %d:%d:%d and DEC: %d*%d:%d", raHour, raMinute, raSecond, decDegree, decMinute, decSecond); calculateRAandDECSteppers(targetRA, targetDEC); + LOGV3(DEBUG_MOUNT, "Mount: Sync Stepper Position is RA: %d and DEC: %d", targetRA, targetDEC); _stepperRA->setCurrentPosition(targetRA); _stepperDEC->setCurrentPosition(targetDEC); } @@ -605,6 +624,10 @@ void Mount::startSlewingToTarget() { stopGuiding(); } + // Make sure we're slewing at full speed on a GoTo + _stepperDEC->setMaxSpeed(_maxDECSpeed); + _stepperRA->setMaxSpeed(_maxRASpeed); + // Calculate new RA stepper target (and DEC) _currentDECStepperPosition = _stepperDEC->currentPosition(); _currentRAStepperPosition = _stepperRA->currentPosition(); @@ -817,7 +840,7 @@ byte Mount::mountStatus() { return _mountStatus; } -#ifdef DEBUG_MODE +#if DEBUG_LEVEL&(DEBUG_MOUNT|DEBUG_MOUNT_VERBOSE) ///////////////////////////////// // // mountStatusString @@ -1033,6 +1056,10 @@ void Mount::startSlewing(int direction) { } else { int sign = NORTHERN_HEMISPHERE ? 1 : -1; + + // Set move rate to last commanded slew rate + setSlewRate(_moveRate); + if (direction & NORTH) { _stepperDEC->moveTo(sign * 30000); _mountStatus |= STATUS_SLEWING; @@ -1115,8 +1142,8 @@ long Mount::getCurrentStepperPosition(int direction) { // ///////////////////////////////// void Mount::delay(int ms) { - long now = millis(); - while (millis() - now < ms) + unsigned long now = millis(); + while (millis() - now < (unsigned long)ms) { loop(); yield(); @@ -1127,6 +1154,7 @@ void Mount::delay(int ms) { // // interruptLoop() // +// This function is run in an ISR. It needs to be fast and do little work. ///////////////////////////////// void Mount::interruptLoop() { @@ -1160,25 +1188,26 @@ void Mount::interruptLoop() // // loop // -// Process any stepper change in movement. +// Process any stepper changes. ///////////////////////////////// void Mount::loop() { bool raStillRunning = false; bool decStillRunning = false; - // Since the ESP8266 cannot process timer interrupts at the required - // speed, we'll just stick to deterministic calls here. -#ifdef ESP8266 + // Since some of the boards cannot process timer interrupts at the required + // speed (or at all), we'll just stick to deterministic calls here. + #if RUN_STEPPERS_IN_MAIN_LOOP == 1 interruptLoop(); -#endif + #endif + #if DEBUG_LEVEL&DEBUG_MOUNT unsigned long now = millis(); -#if defined DEBUG_MODE && defined SEND_PERIODIC_UPDATES if (now - _lastMountPrint > 2000) { Serial.println(getStatusString()); _lastMountPrint = now; -} -#endif + } + #endif + if (isGuiding()) { if (millis() > _guideEndTime) { stopGuiding(); @@ -1207,15 +1236,11 @@ void Mount::loop() { _mountStatus &= ~(STATUS_SLEWING | STATUS_SLEWING_TO_TARGET); if (_stepperWasRunning) { -#ifdef DEBUG_MODE - logv("Loop: Reached target."); -#endif + LOGV1(DEBUG_MOUNT,"Mount::Loop: Reached target."); // Mount is at Target! // If we we're parking, we just reached home. Clear the flag, reset the motors and stop tracking. if (isParking()) { -#ifdef DEBUG_MODE - logv("Loop: Was Parking, stop tracking and set home."); -#endif + LOGV1(DEBUG_MOUNT,"Mount::Loop: Was Parking, stop tracking and set home."); stopSlewing(TRACKING); setHome(); } @@ -1223,40 +1248,28 @@ void Mount::loop() { _currentDECStepperPosition = _stepperDEC->currentPosition(); _currentRAStepperPosition = _stepperRA->currentPosition(); if (_correctForBacklash) { -#ifdef DEBUG_MODE - logv("Loop: Reached target at %d. Compensating by %d", _currentRAStepperPosition, _backlashCorrectionSteps); -#endif + LOGV3(DEBUG_MOUNT,"Mount::Loop: Reached target at %d. Compensating by %d", _currentRAStepperPosition, _backlashCorrectionSteps); _currentRAStepperPosition += _backlashCorrectionSteps; _stepperRA->runToNewPosition(_currentRAStepperPosition); _correctForBacklash = false; -#ifdef DEBUG_MODE - logv("Loop: Backlash correction done. Pos: %d", _currentRAStepperPosition); -#endif + LOGV2(DEBUG_MOUNT,"Mount::Loop: Backlash correction done. Pos: %d", _currentRAStepperPosition); } else { -#ifdef DEBUG_MODE - logv("Loop: Reached target at %d, no backlash compensation needed", _currentRAStepperPosition); -#endif + LOGV2(DEBUG_MOUNT,"Mount::Loop: Reached target at %d, no backlash compensation needed", _currentRAStepperPosition); } if (_slewingToHome) { -#ifdef DEBUG_MODE - logv("Loop: Was Slewing home, so setting stepper RA and TRK to zero."); -#endif + LOGV1(DEBUG_MOUNT,"Mount::Loop: Was Slewing home, so setting stepper RA and TRK to zero."); _stepperRA->setCurrentPosition(0); _stepperTRK->setCurrentPosition(0); _targetRA = currentRA(); if (isParking()) { -#ifdef DEBUG_MODE - logv("Loop: Was parking, so no tracking."); -#endif + LOGV1(DEBUG_MOUNT,"Mount::Loop: Was parking, so no tracking."); _mountStatus &= ~STATUS_PARKING; } else { -#ifdef DEBUG_MODE - logv("Loop: Restart tracking."); -#endif + LOGV1(DEBUG_MOUNT,"Mount::Loop: Restart tracking."); startSlewing(TRACKING); } _slewingToHome = false; @@ -1281,11 +1294,10 @@ void Mount::loop() { // ///////////////////////////////// void Mount::setHome() { -#ifdef DEBUG_MODE - logv("Mount::setHomePre: currentRA is %s", currentRA().ToString()); - logv("Mount::setHomePre: zeroPos is %s", _zeroPosRA.ToString()); - logv("Mount::setHomePre: targetRA is %s", targetRA().ToString()); -#endif + LOGV1(DEBUG_MOUNT,"Mount::setHome() called"); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePre: currentRA is %s", currentRA().ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePre: zeroPos is %s", _zeroPosRA.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePre: targetRA is %s", targetRA().ToString()); _zeroPosRA = currentRA(); _stepperRA->setCurrentPosition(0); @@ -1294,11 +1306,9 @@ void Mount::setHome() { _targetRA = currentRA(); -#ifdef DEBUG_MODE - logv("Mount::setHomePost: currentRA is %s", currentRA().ToString()); - logv("Mount::setHomePost: zeroPos is %s", _zeroPosRA.ToString()); - logv("Mount::setHomePost: targetRA is %s", targetRA().ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePost: currentRA is %s", currentRA().ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePost: zeroPos is %s", _zeroPosRA.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setHomePost: targetRA is %s", targetRA().ToString()); } ///////////////////////////////// @@ -1310,27 +1320,25 @@ void Mount::setHome() { void Mount::setTargetToHome() { float trackedSeconds = _stepperTRK->currentPosition() / _trackingSpeed; // steps/steps/s + LOGV2(DEBUG_MOUNT,"Mount::setTargetToHome() called with %fs elapsed tracking", trackedSeconds); + // In order for RA coordinates to work correctly, we need to // offset HATime by elapsed time since last HA set and also // adjust RA by the elapsed time and set it to zero. -#ifdef DEBUG_MODE - logv("Mount::setTargetToHomePre: currentRA is %s", currentRA().ToString()); - logv("Mount::setTargetToHomePre: ZeroPosRA is %s", _zeroPosRA.ToString()); - logv("Mount::setTargetToHomePre: TrackedSeconds is %f, TRK Stepper: %l", trackedSeconds, _stepperTRK->currentPosition()); - logv("Mount::setTargetToHomePre: LST is %s", _LST.ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePre: currentRA is %s", currentRA().ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePre: ZeroPosRA is %s", _zeroPosRA.ToString()); + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePre: TrackedSeconds is %f, TRK Stepper: %l", trackedSeconds, _stepperTRK->currentPosition()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePre: LST is %s", _LST.ToString()); DayTime lst(_LST); lst.addSeconds(trackedSeconds); setLST(lst); _targetRA = _zeroPosRA; _targetRA.addSeconds(trackedSeconds); -#ifdef DEBUG_MODE - logv("Mount::setTargetToHomePost: currentRA is %s", currentRA().ToString()); - logv("Mount::setTargetToHomePost: ZeroPosRA is %s", _zeroPosRA.ToString()); - logv("Mount::setTargetToHomePost: LST is %s", _LST.ToString()); - logv("Mount::setTargetToHomePost: TargetRA is %s", _targetRA.ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePost: currentRA is %s", currentRA().ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePost: ZeroPosRA is %s", _zeroPosRA.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePost: LST is %s", _LST.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::setTargetToHomePost: TargetRA is %s", _targetRA.ToString()); // Set DEC to pole _targetDEC.set(0, 0, 0); @@ -1366,18 +1374,14 @@ float Mount::getSpeed(int direction) { // This code tells the steppers to what location to move to, given the select right ascension and declination ///////////////////////////////// void Mount::calculateRAandDECSteppers(float& targetRA, float& targetDEC) { -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersPre: Current: RA: %s, DEC: %s", currentRA().ToString(), currentDEC().ToString()); - logv("Mount::CalcSteppersPre: Target : RA: %s, DEC: %s", _targetRA.ToString(), _targetDEC.ToString()); - logv("Mount::CalcSteppersPre: ZeroRA : %s", _zeroPosRA.ToString()); - logv("Mount::CalcSteppersPre: Stepper: RA: %l, DEC: %l, TRK: %l", _stepperRA->currentPosition(), _stepperDEC->currentPosition(), _stepperTRK->currentPosition()); -#endif + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersPre: Current: RA: %s, DEC: %s", currentRA().ToString(), currentDEC().ToString()); + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersPre: Target : RA: %s, DEC: %s", _targetRA.ToString(), _targetDEC.ToString()); + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersPre: ZeroRA : %s", _zeroPosRA.ToString()); + LOGV4(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersPre: Stepper: RA: %l, DEC: %l, TRK: %l", _stepperRA->currentPosition(), _stepperDEC->currentPosition(), _stepperTRK->currentPosition()); DayTime raTarget = _targetRA; raTarget.subtractTime(_zeroPosRA); -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: Adjust RA by Zeropos. New Target RA: %s, DEC: %s", raTarget.ToString(), _targetDEC.ToString()); -#endif + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: Adjust RA by Zeropos. New Target RA: %s, DEC: %s", raTarget.ToString(), _targetDEC.ToString()); float hourPos = raTarget.getTotalHours(); if (!NORTHERN_HEMISPHERE) { @@ -1386,9 +1390,7 @@ void Mount::calculateRAandDECSteppers(float& targetRA, float& targetDEC) { // Map [0 to 24] range to [-12 to +12] range while (hourPos > 12) { hourPos = hourPos - 24; -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: RA>12 so -24. New Target RA: %s, DEC: %s", DayTime(hourPos).ToString(), _targetDEC.ToString()); -#endif + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: RA>12 so -24. New Target RA: %s, DEC: %s", DayTime(hourPos).ToString(), _targetDEC.ToString()); } // How many steps moves the RA ring one sidereal hour along. One sidereal hour moves just shy of 15 degrees @@ -1405,10 +1407,8 @@ void Mount::calculateRAandDECSteppers(float& targetRA, float& targetDEC) { // the variable targetDEC 0deg for the celestial pole (90deg), and goes negative only. float moveDEC = -_targetDEC.getTotalDegrees() * _stepsPerDECDegree; -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: RA Steps/deg: %d Steps/srhour: %f", _stepsPerRADegree, stepsPerSiderealHour); - logv("Mount::CalcSteppersIn: Target Step pos RA: %f, DEC: %f", moveRA, moveDEC); -#endif + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: RA Steps/deg: %d Steps/srhour: %f", _stepsPerRADegree, stepsPerSiderealHour); + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: Target Step pos RA: %f, DEC: %f", moveRA, moveDEC); // We can move 6 hours in either direction. Outside of that we need to flip directions. #if RA_Stepper_TYPE == 0 @@ -1419,43 +1419,31 @@ void Mount::calculateRAandDECSteppers(float& targetRA, float& targetDEC) { // If we reach the limit in the positive direction ... if (moveRA > RALimit) { -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: RA is past +limit: %f, DEC: %f", RALimit); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: RA is past +limit: %f, DEC: %f", RALimit); // ... turn both RA and DEC axis around - float oldRA = moveRA; #if RA_Stepper_TYPE == 0 moveRA -= long(12.0f * stepsPerSiderealHour / 2); #else moveRA -= long(12.0f * stepsPerSiderealHour); #endif moveDEC = -moveDEC; -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: Adjusted Target Step pos RA: %f, DEC: %f", moveRA, moveDEC); -#endif + LOGV3(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: Adjusted Target Step pos RA: %f, DEC: %f", moveRA, moveDEC); } // If we reach the limit in the negative direction... else if (moveRA < -RALimit) { -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersIn: RA is past -limit: %f, DEC: %f", -RALimit); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersIn: RA is past -limit: %f, DEC: %f", -RALimit); // ... turn both RA and DEC axis around - float oldRA = moveRA; #if RA_Stepper_TYPE == 0 moveRA += long(12.0f * stepsPerSiderealHour / 2); #else moveRA += long(12.0f * stepsPerSiderealHour); #endif moveDEC = -moveDEC; -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersPost: Adjusted Target. Moved RA, inverted DEC"); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"Mount::CalcSteppersPost: Adjusted Target. Moved RA, inverted DEC"); } -#ifdef DEBUG_MODE - logv("Mount::CalcSteppersPost: Target Steps RA: %f, DEC: %f", moveRA, moveDEC); -#endif + LOGV3(DEBUG_MOUNT,"Mount::CalcSteppersPost: Target Steps RA: %f, DEC: %f", -moveRA, moveDEC); // float targetRA = clamp(-moveRA, -RAStepperLimit, RAStepperLimit); // float targetDEC = clamp(moveDEC, DECStepperUpLimit, DECStepperDownLimit); targetRA = -moveRA; @@ -1475,15 +1463,11 @@ void Mount::calculateRAandDECSteppers(float& targetRA, float& targetDEC) { void Mount::moveSteppersTo(float targetRA, float targetDEC) { // Show time: tell the steppers where to go! _correctForBacklash = false; -#ifdef DEBUG_MODE - logv("Mount::MoveSteppersTo: RA From: %l To: %f", _stepperRA->currentPosition(), targetRA); - logv("Mount::MoveSteppersTo: DEC From: %l To: %f", _stepperDEC->currentPosition(), targetDEC); -#endif + LOGV3(DEBUG_MOUNT,"Mount::MoveSteppersTo: RA From: %l To: %f", _stepperRA->currentPosition(), targetRA); + LOGV3(DEBUG_MOUNT,"Mount::MoveSteppersTo: DEC From: %l To: %f", _stepperDEC->currentPosition(), targetDEC); if ((_stepperRA->currentPosition() - targetRA) > 0) { -#ifdef DEBUG_MODE - logv("Mount::MoveSteppersTo: Needs backlash correction!"); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"Mount::MoveSteppersTo: Needs backlash correction!"); targetRA -= _backlashCorrectionSteps; _correctForBacklash = true; } @@ -1499,7 +1483,7 @@ void Mount::moveSteppersTo(float targetRA, float targetDEC) { // ///////////////////////////////// void Mount::displayStepperPosition() { -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 String disp; @@ -1529,7 +1513,7 @@ void Mount::displayStepperPosition() { _lcdMenu->printMenu(String(scratchBuffer)); } else { -#ifdef SUPPORT_SERIAL_CONTROL +#if SUPPORT_SERIAL_CONTROL == 1 if (inSerialControl) { sprintf(scratchBuffer, " RA: %s", RAString(LCD_STRING | CURRENT_STRING).c_str()); _lcdMenu->setCursor(0, 0); @@ -1558,7 +1542,7 @@ void Mount::displayStepperPosition() { // ///////////////////////////////// void Mount::displayStepperPositionThrottled() { -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 long elapsed = millis() - _lastDisplayUpdate; if (elapsed > DISPLAY_UPDATE_TIME) { displayStepperPosition(); @@ -1576,24 +1560,16 @@ void Mount::displayStepperPositionThrottled() { String Mount::DECString(byte type, byte active) { DegreeTime dec; if ((type & TARGET_STRING) == TARGET_STRING) { -#ifdef DEBUG_MODE - logv("DECString: TARGET!"); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"DECString: TARGET!"); dec = _targetDEC; } else { -#ifdef DEBUG_MODE - logv("DECString: CURRENT!"); -#endif + LOGV1(DEBUG_MOUNT_VERBOSE,"DECString: CURRENT!"); dec = DegreeTime(currentDEC()); } -#ifdef DEBUG_MODE - logv("DECString: Precheck : %s", dec.ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"DECString: Precheck : %s", dec.ToString()); dec.checkHours(); -#ifdef DEBUG_MODE - logv("DECString: Postcheck : %s", dec.ToString()); -#endif + LOGV2(DEBUG_MOUNT_VERBOSE,"DECString: Postcheck : %s", dec.ToString()); sprintf(scratchBuffer, formatStringsDEC[type & FORMAT_STRING_MASK], dec.getPrintDegrees() > 0 ? '+' : '-', int(fabs(dec.getPrintDegrees())), dec.getMinutes(), dec.getSeconds()); if ((type & FORMAT_STRING_MASK) == LCDMENU_STRING) { diff --git a/Software/Arduino code/OpenAstroTracker/Mount.hpp b/Software/Arduino code/OpenAstroTracker/Mount.hpp index fc9aa73b..706dc14c 100644 --- a/Software/Arduino code/OpenAstroTracker/Mount.hpp +++ b/Software/Arduino code/OpenAstroTracker/Mount.hpp @@ -71,6 +71,9 @@ class Mount { // degree for each axis. This function stores the value in persistent storage void setStepsPerDegree(int which, int steps); + // Sets the slew rate of the mount. rate is between 1 (slowest) and 4 (fastest) + void setSlewRate(int rate); + // Set the HA time (HA is derived from LST, the setter calculates and sets LST) void setHA(const DayTime& haTime); const DayTime HA() const; @@ -185,6 +188,9 @@ class Mount { // Called when startup is complete and the mount needs to start updating steppers. void startTimerInterrupts(); + // Read the saved configuration from persistent storage + void readConfiguration(); + private: // Reads values from EEPROM that configure the mount (if previously stored) @@ -204,7 +210,7 @@ class Mount { // Returns some combination of these flags: STATUS_PARKED, STATUS_SLEWING, STATUS_SLEWING_TO_TARGET, STATUS_SLEWING_FREE, STATUS_TRACKING, STATUS_PARKING byte mountStatus(); -#ifdef DEBUG_MODE +#if DEBUG_LEVEL&(DEBUG_MOUNT|DEBUG_MOUNT_VERBOSE) String mountStatusString(); #endif @@ -218,6 +224,7 @@ class Mount { int _maxRAAcceleration; int _maxDECAcceleration; int _backlashCorrectionSteps; + int _moveRate; long _lastHASet; DayTime _LST; diff --git a/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.hpp b/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.hpp index 878ebd44..7a68b27a 100644 --- a/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.hpp +++ b/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.hpp @@ -1,7 +1,7 @@ /* ======================================================================================================================================= - Version 1.6 + Version 1.7 1. Connect your Arduino, under tools choose "Arduino Uno", set the right Port and set "Arduino ISP" as the Programmer. 2. Hit upload (Ctrl-U) @@ -14,22 +14,24 @@ ======================================================================================================================================= */ +#pragma once + #include "Globals.hpp" -String version = "V1.7.04"; +String version = "V1.7.15"; /////////////////////////////////////////////////////////////////////////// // Please see the Globals.h file for configuration of the firmware. /////////////////////////////////////////////////////////////////////////// -// See NORTHERN_HEMISPHERE in Globals.h if you not in the northern hemisphere - - -// RA stepper ////////////////////////////////////////////////////////////////////////////////// +// See NORTHERN_HEMISPHERE in Globals.hpp if you NOT in the northern hemisphere +/////////////////////////////////////////////////////////////////////////// +// RA stepper // +/////////////////////////////////////////////////////////////////////////// // This is how many steps your 28BYJ-48 stepper needs for a full rotation. It is almost always 4096. -// This code drives the steppers in halfstep mode for TRK and DEC, and full step for RA +// This code drives the stepper in halfstep mode for TRK and DEC, and full step mode for RA float RAStepsPerRevolution = 4096; // The radius of the surface that the belt runs on (in V1 of the ring) was 168.24mm. @@ -38,55 +40,43 @@ float RAStepsPerRevolution = 4096; // One RA revolution needs 26.43 (1057.1mm / 40mm) stepper revolutions (V2: 28.27 (1131mm/40mm)) // Which means 108245 steps (26.43 x 4096) moves 360 degrees (V2: 115812 steps (28.27 x 4096)) // So there are 300.1 steps/degree (108245 / 360) (V2: 322 (115812 / 360)) -// Theoretically correct RA tracking speed is 1.246586 (300 x 14.95903 / 3600) (V2 : 1.333800 (322 x 14.95903 / 3600) steps/sec +// Theoretically correct RA tracking speed is 1.246586 (300 x 14.95903 / 3600) (V2 : 1.333800 (322 x 14.95903 / 3600) steps/sec (this is for 20T) // Your drive pulley tooth count: #define RAPulleyTeeth 16 + // the Circumference of the RA wheel // V1: 1057.1 // V2: 1131 #define RACircumference 1131 int RAStepsPerDegree = (RACircumference / (RAPulleyTeeth * 2.0) * RAStepsPerRevolution / 360.0); // V2 Ring has belt in a groove and belt runs on bearings +int RAspeed = 400; // You can change the speed and acceleration of the steppers here. Max. Speed = 600. +int RAacceleration = 600; // High speeds tend to make these cheap steppers unprecice - -// DEC stepper ////////////////////////////////////////////////////////////////////////////////// - +/////////////////////////////////////////////////////////////////////////// +// DEC stepper // +/////////////////////////////////////////////////////////////////////////// +// This is how many steps your 28BYJ-48 stepper needs for a full rotation. It is almost always 4096. +// This code drives the DEC stepper in halfstep mode float DECStepsPerRevolution = 4096; // Belt moves 40mm for one stepper revolution (2mm pitch, 20 teeth). // DEC wheel is 2 x PI x 90mm circumference which is 565.5mm // One DEC revolution needs 14.13 (565.5mm/40mm) stepper revolutions // Which means 57907 steps (14.14 x 4096) moves 360 degrees -// So there are 160.85 steps/degree (57907/360) +// So there are 160.85 steps/degree (57907/360) (this is for 20T) #define DecPulleyTeeth 16 int DECStepsPerDegree = (565.5 / (DecPulleyTeeth * 2.0) * DECStepsPerRevolution / 360.0); - -int RAspeed = 400; // You can change the speed and acceleration of the steppers here. Max. Speed = 600. High speeds tend to make -int RAacceleration = 600; // these cheap steppers unprecice -int DECspeed = 800; -int DECacceleration = 400; - -// Define some stepper limits to prevent physical damage to the tracker. This assumes that the home -// point (zero point) has been correctly set to be pointing at the celestial pole. -// Note: these are currently not used -float RAStepperLimit = 15500; // Going much more than this each direction will make the ring fall off the bearings. - -// These are for 47N, so they will need adjustment if you're a lot away from that. -// You can use the CTRL menu to find the limits and place them here. I moved it -// down until my lens was horizontal. Note the DEC number. Then move it up until -// the lens is horizontal and note that number. Put those here. Always watch your -// tracker and hit RESET if it approaches a dangerous area. -// Note: these are currently not used -float DECStepperDownLimit = 10000; // Going much more than this will make the lens collide with the ring -float DECStepperUpLimit = -22000; // Going much more than this is going below the horizon. +int DECspeed = 600; // You can change the speed and acceleration of the steppers here. Max. Speed = 600. +int DECacceleration = 400; // High speeds tend to make these cheap steppers unprecice // These values are needed to calculate the current position during initial alignment. -int PolarisRAHour = 2; -int PolarisRAMinute = 58; -int PolarisRASecond = 4; // Use something like Stellarium to look up the RA of Polaris in JNow (on date) variant. // This changes slightly over weeks, so adjust every couple of months. -// This value is from 18.Apr.2020, next adjustment suggested at end 2020 +// This value is from 15.Jun.2020, next adjustment suggested at end 2020 // The same could be done for the DEC coordinates but they dont change significantly for the next 5 years +byte PolarisRAHour = 2; +byte PolarisRAMinute = 58; +byte PolarisRASecond = 15; diff --git a/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.ino b/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.ino index c5cafe41..542b1389 100644 --- a/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.ino +++ b/Software/Arduino code/OpenAstroTracker/OpenAstroTracker.ino @@ -1,5 +1,4 @@ -// Use OpenAstroTracker.hpp and Globals.hpp for configuration! - +// Configuration is now done in OpenAstroTracker.hpp and Globals.hpp #include "OpenAstroTracker.hpp" #include "a_inits.hpp" #include "b_setup.hpp" diff --git a/Software/Arduino code/OpenAstroTracker/TimerInterrupt.h b/Software/Arduino code/OpenAstroTracker/TimerInterrupt.h index e05c8978..82fcbbde 100644 --- a/Software/Arduino code/OpenAstroTracker/TimerInterrupt.h +++ b/Software/Arduino code/OpenAstroTracker/TimerInterrupt.h @@ -33,9 +33,7 @@ #define TIMER_INTERRUPT_DEBUG 0 #endif -#if defined(ESP8266) || defined(ESP32) -#error This code is designed to run on Arduino AVR (Nano, UNO, Mega, etc.) platform, not ESP8266 nor ESP32! Please check your Tools->Board setting. -#endif +#if !defined(ESP8266) && !defined(ESP32) #include #include @@ -626,3 +624,5 @@ ISR(TIMER5_COMPA_vect) #endif //#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) #endif //#ifndef TimerInterrupt_h + +#endif \ No newline at end of file diff --git a/Software/Arduino code/OpenAstroTracker/Utility.cpp b/Software/Arduino code/OpenAstroTracker/Utility.cpp index 9f5a7012..10ac5d02 100644 --- a/Software/Arduino code/OpenAstroTracker/Utility.cpp +++ b/Software/Arduino code/OpenAstroTracker/Utility.cpp @@ -1,24 +1,27 @@ #include -#ifdef DEBUG_MODE +#if DEBUG_LEVEL > 0 #include #endif #include "Utility.hpp" -#ifdef DEBUG_MODE +#if DEBUG_LEVEL > 0 unsigned long RealTime::_pausedTime = 0; unsigned long RealTime::_startTime = micros(); unsigned long RealTime::_suspendStart = 0; int RealTime::_suspended = 0; #endif + // Adjust the given number by the given adjustment, wrap around the limits. // Limits are inclusive, so they represent the lowest and highest valid number. int adjustWrap(int current, int adjustBy, int minVal, int maxVal) { current += adjustBy; - if (current > maxVal) current -= (maxVal + 1 - minVal); - if (current < minVal) current += (maxVal + 1 - minVal); + if (current > maxVal) + current -= (maxVal + 1 - minVal); + if (current < minVal) + current += (maxVal + 1 - minVal); return current; } @@ -27,8 +30,10 @@ int adjustWrap(int current, int adjustBy, int minVal, int maxVal) int adjustClamp(int current, int adjustBy, int minVal, int maxVal) { current += adjustBy; - if (current > maxVal) current = maxVal; - if (current < minVal) current = minVal; + if (current > maxVal) + current = maxVal; + if (current < minVal) + current = minVal; return current; } @@ -36,96 +41,123 @@ int adjustClamp(int current, int adjustBy, int minVal, int maxVal) // Limits are inclusive, so they represent the lowest and highest valid number. long clamp(long current, long minVal, long maxVal) { - if (current > maxVal) current = maxVal; - if (current < minVal) current = minVal; + if (current > maxVal) + current = maxVal; + if (current < minVal) + current = minVal; return current; } // Clamp the given number to the limits. // Limits are inclusive, so they represent the lowest and highest valid number. -float clamp(float current, float minVal, float maxVal) +int clamp(int current, int minVal, int maxVal) { - if (current > maxVal) current = maxVal; - if (current < minVal) current = minVal; + if (current > maxVal) + current = maxVal; + if (current < minVal) + current = minVal; return current; } +// Clamp the given number to the limits. +// Limits are inclusive, so they represent the lowest and highest valid number. +float clamp(float current, float minVal, float maxVal) +{ + if (current > maxVal) + current = maxVal; + if (current < minVal) + current = minVal; + return current; +} -#ifdef DEBUG_MODE +#if DEBUG_LEVEL > 0 -String formatArg(const char* input, va_list args) { - char* nibble = "0123456789ABCDEF"; +String formatArg(const char *input, va_list args) +{ + const char *nibble = "0123456789ABCDEF"; char achBuffer[255]; - char* p = achBuffer; + char *p = achBuffer; - for (const char* i = input; *i != 0; i++) { - if (*i != '%') { + for (const char *i = input; *i != 0; i++) + { + if (*i != '%') + { *p++ = *i; continue; } i++; - switch (*i) { - case '%': { - *p++ = '%'; - } - break; + switch (*i) + { + case '%': + { + *p++ = '%'; + } + break; - case 'c': { - char* ch = va_arg(args, char*); - *p++ = *ch; - } - break; + case 'c': + { + char *ch = va_arg(args, char *); + *p++ = *ch; + } + break; - case 's': { - char* s = va_arg(args, char*); - strcpy(p, s); - p += strlen(s); - } - break; + case 's': + { + char *s = va_arg(args, char *); + strcpy(p, s); + p += strlen(s); + } + break; - case 'd': { - String s = String((int)va_arg(args, int)); - strcpy(p, s.c_str()); - p += s.length(); - } - break; - - case 'x': { - int n = (int)va_arg(args, int); - int shift = 12; - unsigned int mask = 0xF000; - *p++ = '0'; - *p++ = 'x'; - while (shift >= 0) { - int d=(n & mask) >> shift; - *p++ = *(nibble + d); - mask = mask >> 4; - shift -= 4; - } - - *p = 0; + case 'd': + { + String s = String((int)va_arg(args, int)); + strcpy(p, s.c_str()); + p += s.length(); + } + break; + + case 'x': + { + int n = (int)va_arg(args, int); + int shift = 12; + unsigned int mask = 0xF000; + *p++ = '0'; + *p++ = 'x'; + while (shift >= 0) + { + int d = (n & mask) >> shift; + *p++ = *(nibble + d); + mask = mask >> 4; + shift -= 4; } - break; - case 'l': { - String s = String((long)va_arg(args, long)); - strcpy(p, s.c_str()); - p += s.length(); - } - break; + *p = 0; + } + break; - case 'f': { - float num = (float)va_arg(args, double); - String s = String(num, 4); - strcpy(p, s.c_str()); - p += s.length(); - } - break; + case 'l': + { + String s = String((long)va_arg(args, long)); + strcpy(p, s.c_str()); + p += s.length(); + } + break; + + case 'f': + { + float num = (float)va_arg(args, double); + String s = String(num, 4); + strcpy(p, s.c_str()); + p += s.length(); + } + break; - default: { - *p++ = *i; - } - break; + default: + { + *p++ = *i; + } + break; } } @@ -133,7 +165,8 @@ String formatArg(const char* input, va_list args) { return String(achBuffer); } -String format(const char* input, ...) { +String format(const char *input, ...) +{ va_list argp; va_start(argp, input); String ret = formatArg(input, argp); @@ -141,22 +174,26 @@ String format(const char* input, ...) { return ret; } -void log(const char* input) { - Serial.println(input); - Serial.flush(); -} +// void log(const char* input) { +// Serial.println(input); +// Serial.flush(); +// } -void log(String input) { - Serial.println(input); - Serial.flush(); -} +// void log(String input) { +// Serial.println(input); +// Serial.flush(); +// } -void logv(const char* input, ...) { - va_list argp; - va_start(argp, input); - Serial.println(formatArg(input, argp)); - Serial.flush(); - va_end(argp); +void logv(int levelFlags, const char *input, ...) +{ + if ((levelFlags & DEBUG_LEVEL) != 0) + { + va_list argp; + va_start(argp, input); + Serial.println(formatArg(input, argp)); + Serial.flush(); + va_end(argp); + } } #endif diff --git a/Software/Arduino code/OpenAstroTracker/Utility.hpp b/Software/Arduino code/OpenAstroTracker/Utility.hpp index 47de8522..fb2f5615 100644 --- a/Software/Arduino code/OpenAstroTracker/Utility.hpp +++ b/Software/Arduino code/OpenAstroTracker/Utility.hpp @@ -12,8 +12,18 @@ #define btnSELECT 4 #define btnNONE 5 -#ifdef DEBUG_MODE - +#if DEBUG_LEVEL>0 + +#define LOGV1(level,a) logv((level),(a)) +#define LOGV2(level,a,b) logv((level),(a),(b)) +#define LOGV3(level,a,b,c) logv((level),(a),(b),(c)) +#define LOGV4(level,a,b,c,d) logv((level),(a),(b),(c),(d)) +#define LOGV5(level,a,b,c,d,e) logv((level),(a),(b),(c),(d),(e)) +#define LOGV6(level,a,b,c,d,e,f) logv((level),(a),(b),(c),(d),(e),(f)) +#define LOGV7(level,a,b,c,d,e,f,g) logv((level),(a),(b),(c),(d),(e),(f),(g)) +#define LOGV8(level,a,b,c,d,e,f,g,h) logv((level),(a),(b),(c),(d),(e),(f),(g),(h)) + +// Realtime timer class using microseconds to time stuff class RealTime { static unsigned long _pausedTime; static unsigned long _startTime; @@ -47,6 +57,7 @@ class RealTime { } }; +// Performance measurement class class PerfMeasure { unsigned long _start; unsigned long _end; @@ -106,11 +117,21 @@ class PerfMeasure { String formatArg(const char* input, va_list args); String format(const char* input, ...); -void log(const char* input); -void log(String input); -void logv(const char* input, ...); +// void log(const char* input); +// void log(String input); +void logv(int levelFlags, const char* input, ...); -#endif +#else // DEBUG_LEVEL>0 + +#define LOGV1(level,a) +#define LOGV2(level,a,b) +#define LOGV3(level,a,b,c) +#define LOGV4(level,a,b,c,d) +#define LOGV5(level,a,b,c,d,e) +#define LOGV6(level,a,b,c,d,e,f) +#define LOGV7(level,a,b,c,d,e,f,g) + +#endif // DEBUG_LEVEL>0 class LcdButtons { public: @@ -167,7 +188,6 @@ class LcdButtons { else { // If the keys haven't changed in 5ms, commit the change to the new keys. if (millis() - _lastKeyChange > 5) { - // Serial.println("KBD: New=" + String(_currentKey )); _newKey = _currentKey; } } @@ -197,6 +217,10 @@ int adjustClamp(int current, int adjustBy, int minVal, int maxVal); // Limits are inclusive, so they represent the lowest and highest valid number. long clamp(long current, long minVal, long maxVal); +// Clamp the given number to the limits. +// Limits are inclusive, so they represent the lowest and highest valid number. +int clamp(int current, int minVal, int maxVal); + // Clamp the given number to the limits. // Limits are inclusive, so they represent the lowest and highest valid number. float clamp(float current, float minVal, float maxVal); diff --git a/Software/Arduino code/OpenAstroTracker/WifiControl.cpp b/Software/Arduino code/OpenAstroTracker/WifiControl.cpp index 8eaf5d57..4e36b4de 100644 --- a/Software/Arduino code/OpenAstroTracker/WifiControl.cpp +++ b/Software/Arduino code/OpenAstroTracker/WifiControl.cpp @@ -1,6 +1,7 @@ #include "WifiControl.hpp" +#include "Utility.hpp" + #ifdef WIFI_ENABLED -#include "ESP8266Wifi.h" #define PORT 4030 @@ -12,9 +13,7 @@ WifiControl::WifiControl(Mount* mount, LcdMenu* lcdMenu) void WifiControl::setup() { -#ifdef DEBUG_MODE - Serial.printf("Starting up Wifi As Mode %d\n", WIFI_MODE); -#endif + LOGV2(DEBUG_WIFI,"Wifi: Starting up Wifi As Mode %d\n", WIFI_MODE); _cmdProcessor = MeadeCommandProcessor::instance(); @@ -34,27 +33,34 @@ void WifiControl::setup() { void WifiControl::startInfrastructureMode() { -#ifdef DEBUG_MODE - Serial.println("Starting Infrastructure Mode Wifi"); - Serial.println(" with host name: "+String(HOSTNAME)); - Serial.println(" for SSID: "+String(INFRA_SSID)); - Serial.println(" and WPA key: "+String(INFRA_WPAKEY)); -#endif + LOGV1(DEBUG_WIFI,"Wifi: Starting Infrastructure Mode Wifi"); + LOGV2(DEBUG_WIFI,"Wifi: with host name: %s", String(HOSTNAME).c_str()); + LOGV2(DEBUG_WIFI,"Wifi: for SSID: %s", String(INFRA_SSID).c_str()); + LOGV2(DEBUG_WIFI,"Wifi: and WPA key: %s", String(INFRA_WPAKEY).c_str()); + +#if defined(ESP8266) WiFi.hostname(HOSTNAME); +#elif defined(ESP32) + WiFi.setHostname(HOSTNAME); +#endif WiFi.begin(INFRA_SSID, INFRA_WPAKEY); } void WifiControl::startAccessPointMode() { -#ifdef DEBUG_MODE - Serial.println("Starting AP Mode Wifi"); -#endif + LOGV1(DEBUG_WIFI,"Wifi: Starting AP Mode Wifi"); IPAddress local_ip(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); +#if defined(ESP8266) WiFi.hostname(HOSTNAME); +#elif defined(ESP32) + WiFi.setHostname(HOSTNAME); +#endif + WiFi.softAP(HOSTNAME, OAT_WPAKEY); + WiFi.softAPConfig(local_ip, gateway, subnet); } @@ -71,37 +77,36 @@ String wifiStatus(int status){ String WifiControl::getStatus() { - return "1," + wifiStatus(WiFi.status()) + "," + WiFi.hostname() + "," += WiFi.localIP().toString() + ":" + PORT; + String result = "1," + wifiStatus(WiFi.status()) + ","; +#ifdef ESP8266 + result += WiFi.hostname(); +#elif defined(ESP32) + result += WiFi.getHostname(); +#endif + + result += "," + WiFi.localIP().toString() + ":" + PORT; + return result; } void WifiControl::loop() { - if (_status != WiFi.status()) { _status = WiFi.status(); -#ifdef DEBUG_MODE - Serial.println("Connected status changed to " + wifiStatus(_status)); -#endif + LOGV2(DEBUG_WIFI,"Wifi: Connected status changed to %s", wifiStatus(_status).c_str()); if (_status == WL_CONNECTED) { _tcpServer = new WiFiServer(PORT); _tcpServer->begin(); _tcpServer->setNoDelay(true); -#ifdef DEBUG_MODE - Serial.println("Server status is "+ wifiStatus( _tcpServer->status())); +#if defined(ESP8266) + LOGV2(DEBUG_WIFI,"Wifi: Server status is %s", wifiStatus( _tcpServer->status()).c_str()); #endif _udp = new WiFiUDP(); _udp->begin(4031); -#ifdef DEBUG_MODE - Serial.print("Connecting to SSID "); - Serial.print(INFRA_SSID); - Serial.print(" IP: "); - Serial.print(WiFi.localIP()); - Serial.print(":"); - Serial.println(String(PORT)); -#endif + LOGV4(DEBUG_WIFI,"Wifi: Connecting to SSID %s at %s:%d", INFRA_SSID, WiFi.localIP().toString().c_str(), PORT); } } + _mount->loop(); if (_status != WL_CONNECTED) { @@ -122,9 +127,7 @@ void WifiControl::infraToAPFailover() { startAccessPointMode(); _infraStart = 0; -#ifdef DEBUG_MODE - Serial.println("Could not connect to Infra, Starting AP."); -#endif + LOGV1(DEBUG_WIFI,"Wifi: Could not connect to Infra, Starting AP."); } } @@ -132,16 +135,12 @@ void WifiControl::tcpLoop() { if (client && client.connected()) { while (client.available()) { String cmd = client.readStringUntil('#'); -#ifdef DEBUG_MODE - Serial.println("<-- "+ cmd + "#"); -#endif - auto retVal = _cmdProcessor->processCommand(cmd); + LOGV2(DEBUG_WIFI,"WifiTCP: Query <-- %s#", cmd.c_str()); + String retVal = _cmdProcessor->processCommand(cmd); if (retVal != "") { client.write(retVal.c_str()); -#ifdef DEBUG_MODE - Serial.println("--> " + retVal); -#endif + LOGV2(DEBUG_WIFI,"WifiTCP: Reply --> %s", retVal.c_str()); } _mount->loop(); @@ -150,7 +149,6 @@ void WifiControl::tcpLoop() { else { client = _tcpServer->available(); } - } void WifiControl::udpLoop() @@ -164,15 +162,11 @@ void WifiControl::udpLoop() reply += HOSTNAME; reply += "@"; reply += WiFi.localIP().toString(); -#ifdef DEBUG_MODE - Serial.printf("Received %d bytes from %s, port %d\n", packetSize, _udp->remoteIP().toString().c_str(), _udp->remotePort()); -#endif + LOGV4(DEBUG_WIFI,"WifiUDP: Received %d bytes from %s, port %d", packetSize, _udp->remoteIP().toString().c_str(), _udp->remotePort()); char incomingPacket[255]; int len = _udp->read(incomingPacket, 255); incomingPacket[len] = 0; -#ifdef DEBUG_MODE - Serial.printf("Received: %s\n", incomingPacket); -#endif + LOGV2(DEBUG_WIFI,"WifiUDP: Received: %s", incomingPacket); incomingPacket[lookingFor.length()] = 0; if (lookingFor.equalsIgnoreCase(incomingPacket)) { @@ -181,11 +175,14 @@ void WifiControl::udpLoop() reply.getBytes(bytes, 255); _udp->write(bytes, reply.length());*/ +#if defined(ESP8266) _udp->write(reply.c_str()); - _udp->endPacket(); -#ifdef DEBUG_MODE - Serial.printf("Replied: %s\n", reply.c_str()); +#elif defined(ESP32) + _udp->print(reply.c_str()); #endif + + _udp->endPacket(); + LOGV2(DEBUG_WIFI,"WifiUDP: Replied: %s", reply.c_str()); } } } diff --git a/Software/Arduino code/OpenAstroTracker/WifiControl.hpp b/Software/Arduino code/OpenAstroTracker/WifiControl.hpp index a7350def..573fba4a 100644 --- a/Software/Arduino code/OpenAstroTracker/WifiControl.hpp +++ b/Software/Arduino code/OpenAstroTracker/WifiControl.hpp @@ -2,13 +2,22 @@ #include "Globals.hpp" #ifdef WIFI_ENABLED -#include "Mount.hpp"; -#include "LcdMenu.hpp"; +#include "Mount.hpp" +#include "LcdMenu.hpp" #include "MeadeCommandProcessor.hpp" #include "WiFiServer.h" #include "WiFiUDP.h" #include "WiFiClient.h" +#ifdef ESP8266 +#include "ESP8266Wifi.h" +#endif + +#ifdef ESP32 +#include +#include +#endif + class WifiControl { public: WifiControl(Mount* mount, LcdMenu* lcdMenu); @@ -30,8 +39,8 @@ class WifiControl { WiFiUDP* _udp; WiFiClient client; - long _infraStart = 0; - int _infraWait = 30000; // 30 second timeout for + unsigned long _infraStart = 0; + unsigned long _infraWait = 30000; // 30 second timeout for }; extern WifiControl wifiControl; diff --git a/Software/Arduino code/OpenAstroTracker/a_inits.hpp b/Software/Arduino code/OpenAstroTracker/a_inits.hpp index 089865c2..a59ae88a 100644 --- a/Software/Arduino code/OpenAstroTracker/a_inits.hpp +++ b/Software/Arduino code/OpenAstroTracker/a_inits.hpp @@ -1,11 +1,7 @@ -// If you really want to look through this code, i apologise for my terrible coding - #pragma once //#include -#include #include -//#include #include #include "Utility.hpp" @@ -13,19 +9,16 @@ #include "Mount.hpp" #include "MeadeCommandProcessor.hpp" - #define HALFSTEP 8 #define FULLSTEP 4 #define DRIVER 1 -//SoftwareSerial BT(10,11); - /////////////////////////////////////////////////////////////////////////// // ESP8266 Wifi Board (NodeMCU) /////////////////////////////////////////////////////////////////////////// #ifdef ESP8266 // RA Motor pins - #ifdef INVERT_RA_DIR + #if INVERT_RA_DIR == 1 #define RAmotorPin1 D0 // IN1 auf ULN2003 driver 1 #define RAmotorPin3 D1 // IN2 auf ULN2003 driver 1 #define RAmotorPin2 D2 // IN3 auf ULN2003 driver 1 @@ -38,7 +31,7 @@ #endif // DEC Motor pins - #ifdef INVERT_DEC_DIR + #if INVERT_DEC_DIR == 1 #define DECmotorPin1 D5 // IN1 auf ULN2003 driver 2 #define DECmotorPin3 D6 // IN3 auf ULN2003 driver 2 #define DECmotorPin2 D7 // IN2 auf ULN2003 driver 2 @@ -57,13 +50,51 @@ #define st4East SD3 #endif + +/////////////////////////////////////////////////////////////////////////// +// ESP32 Wifi Board +/////////////////////////////////////////////////////////////////////////// +#ifdef ESP32 +// RA Motor pins + #if INVERT_RA_DIR == 1 + #define RAmotorPin1 35 // IN1 auf ULN2003 driver 1 + #define RAmotorPin3 34 // IN2 auf ULN2003 driver 1 + #define RAmotorPin2 39 // IN3 auf ULN2003 driver 1 + #define RAmotorPin4 36 // IN4 auf ULN2003 driver 1 + #else + #define RAmotorPin1 23 // IN1 auf ULN2003 driver 1 + #define RAmotorPin3 22 // IN2 auf ULN2003 driver 1 + #define RAmotorPin2 21 // IN3 auf ULN2003 driver 1 + #define RAmotorPin4 19 // IN4 auf ULN2003 driver 1 + #endif + +// DEC Motor pins + #if INVERT_DEC_DIR == 1 + #define DECmotorPin1 26 // IN1 auf ULN2003 driver 2 + #define DECmotorPin3 25 // IN3 auf ULN2003 driver 2 + #define DECmotorPin2 33 // IN2 auf ULN2003 driver 2 + #define DECmotorPin4 32 // IN4 auf ULN2003 driver 2 + #else + #define DECmotorPin1 18 // IN1 auf ULN2003 driver 2 + #define DECmotorPin3 5 // IN3 auf ULN2003 driver 2 + #define DECmotorPin2 17 // IN2 auf ULN2003 driver 2 + #define DECmotorPin4 16 // IN4 auf ULN2003 driver 2 + #endif + +// ST4 Input Pins - TODO. + /*#define st4North SD0 + #define st4South SD1 + #define st4West SD2 + #define st4East SD3*/ +#endif + /////////////////////////////////////////////////////////////////////////// // Arduino Uno /////////////////////////////////////////////////////////////////////////// #ifdef __AVR_ATmega328P__ // normal Arduino Mapping #if RA_Stepper_TYPE == 0 // 28BYJ // RA Motor pins - #ifdef INVERT_RA_DIR + #if INVERT_RA_DIR == 1 #define RAmotorPin1 12 // IN1 auf ULN2003 driver 1 #define RAmotorPin3 11 // IN2 auf ULN2003 driver 1 #define RAmotorPin2 3 // IN3 auf ULN2003 driver 1 @@ -82,7 +113,7 @@ // DEC Motor pins #if DEC_Stepper_TYPE == 0 // 28BYJ - #ifdef INVERT_DEC_DIR + #if INVERT_DEC_DIR == 1 #define DECmotorPin1 18 // IN1 auf ULN2003 driver 2 #define DECmotorPin2 16 // IN2 auf ULN2003 driver 2 #define DECmotorPin3 17 // IN3 auf ULN2003 driver 2 @@ -107,7 +138,7 @@ #ifdef __AVR_ATmega2560__ // Arduino Mega #if RA_Stepper_TYPE == 0 // 28BYJ // RA Motor pins - #ifdef INVERT_RA_DIR + #if INVERT_RA_DIR == 1 #define RAmotorPin1 22 // IN1 auf ULN2003 driver 1 #define RAmotorPin3 24 // IN2 auf ULN2003 driver 1 #define RAmotorPin2 26 // IN3 auf ULN2003 driver 1 @@ -126,7 +157,7 @@ // DEC Motor pins #if DEC_Stepper_TYPE == 0 // 28BYJ - #ifdef INVERT_DEC_DIR + #if INVERT_DEC_DIR == 1 #define DECmotorPin1 36 // IN1 auf ULN2003 driver 2 #define DECmotorPin3 34 // IN2 auf ULN2003 driver 2 #define DECmotorPin2 32 // IN3 auf ULN2003 driver 2 @@ -160,7 +191,7 @@ // How many menu items at most? #define MAXMENUITEMS 10 -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 bool inStartup = true; // Start with a guided startup #else bool inStartup = false; // Start with a guided startup @@ -185,7 +216,7 @@ int DECselect; // HA variables int HAselect; -#ifdef SUPPORT_HEATING +#if SUPPORT_HEATING == 1 // HEAT menu variables int heatselect; // Which stepper are we changing? int RAheat = 0; // Are we heating the RA stepper? diff --git a/Software/Arduino code/OpenAstroTracker/b_setup.hpp b/Software/Arduino code/OpenAstroTracker/b_setup.hpp index fd3e79d9..9774b298 100644 --- a/Software/Arduino code/OpenAstroTracker/b_setup.hpp +++ b/Software/Arduino code/OpenAstroTracker/b_setup.hpp @@ -2,16 +2,75 @@ #pragma once +#include "OpenAstroTracker.hpp" +#include "a_inits.hpp" +#include "LcdMenu.hpp" +#include "Utility.hpp" +#include "EPROMStore.hpp" + LcdMenu lcdMenu(16, 2, MAXMENUITEMS); LcdButtons lcdButtons(0); +#ifdef ESP32 +DRAM_ATTR Mount mount(RAStepsPerDegree, DECStepsPerDegree, &lcdMenu); +#else Mount mount(RAStepsPerDegree, DECStepsPerDegree, &lcdMenu); +#endif #ifdef WIFI_ENABLED #include "WifiControl.hpp" WifiControl wifiControl(&mount, &lcdMenu); #endif +void finishSetup(); + +///////////////////////////////// +// ESP32 +///////////////////////////////// +#if defined(ESP32) && (RUN_STEPPERS_IN_MAIN_LOOP == 0) +// Forward declare the two functions we run in the main loop +void serialLoop(); + +TaskHandle_t StepperTask; +TaskHandle_t CommunicationsTask; + +///////////////////////////////// +// +// stepperControlFunc +// +// This task function is run on Core 1 of the ESP32 +///////////////////////////////// +void IRAM_ATTR stepperControlTask(void* payload) +{ + Mount* mount = reinterpret_cast(payload); + for (;;) { + mount->interruptLoop(); + vTaskDelay(1); + } +} + +///////////////////////////////// +// +// mainLoopFunc +// +// This task function is run on Core 2 of the ESP32 +///////////////////////////////// +void IRAM_ATTR mainLoopTask(void* payload) +{ + finishSetup(); + + for (;;) { + serialLoop(); + vTaskDelay(1); + } +} +#endif + +///////////////////////////////// +// +// Main program setup +// +///////////////////////////////// void setup() { // Microstepping --------------- @@ -31,21 +90,58 @@ void setup() { digitalWrite(44, HIGH); // MS1 #endif - //debug_init(); Serial.begin(57600); //BT.begin(9600); -#ifdef DEBUG_MODE - Serial.println("Hello, universe!"); + LOGV2(DEBUG_ANY, "Hello, universe, this is OAT %s!", version.c_str()); + + EPROMStore::initialize(); + +///////////////////////////////// +// ESP32 +///////////////////////////////// +#if defined(ESP32) && (RUN_STEPPERS_IN_MAIN_LOOP == 0) + disableCore0WDT(); + xTaskCreatePinnedToCore( + stepperControlTask, // Function to run on this core + "StepperControl", // Name of this task + 32767, // Stack space in bytes + &mount, // payload + 2, // Priority (2 is higher than 1) + &StepperTask, // The location that receives the thread id + 0); // The core to run this on + + delay(100); + + xTaskCreatePinnedToCore( + mainLoopTask, // Function to run on this core + "CommunicationControl", // Name of this task + 32767, // Stack space in bytes + NULL, // payload + 1, // Priority (2 is higher than 1) + &CommunicationsTask, // The location that receives the thread id + 1); // The core to run this on + + delay(100); + +#else + + finishSetup(); + #endif +} +void finishSetup() +{ + LOGV1(DEBUG_ANY, "Finishing setup..."); // Show a splash screen lcdMenu.setCursor(0, 0); lcdMenu.printMenu("OpenAstroTracker"); lcdMenu.setCursor(0, 1); lcdMenu.printMenu(" " + version); +#if HEADLESS_CLIENT == 0 unsigned long now = millis(); - +#endif // Create the command processor singleton MeadeCommandProcessor::createProcessor(&mount, &lcdMenu); @@ -71,14 +167,14 @@ void setup() { #endif // The mount uses EEPROM storage locations 0-10 that it reads during construction - + // The LCD uses EEPROM storage location 11 + mount.readConfiguration(); + // Read other persisted values and set in mount - DayTime haTime = DayTime(EEPROM.read(1), EEPROM.read(2), 0); + DayTime haTime = DayTime(EPROMStore::Storage()->read(1), EPROMStore::Storage()->read(2), 0); -#ifdef DEBUG_MODE - Serial.println("SpeedCal: " + String(mount.getSpeedCalibration(), 5)); - Serial.println("TRKSpeed: " + String(mount.getSpeed(TRACKING), 5)); -#endif + LOGV2(DEBUG_INFO, "SpeedCal: %s", String(mount.getSpeedCalibration(), 5).c_str()); + LOGV2(DEBUG_INFO, "TRKSpeed: %s", String(mount.getSpeed(TRACKING), 5).c_str()); mount.setHA(haTime); @@ -91,12 +187,12 @@ void setup() { // Start the tracker. mount.startSlewing(TRACKING); -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 // Create the LCD top-level menu items lcdMenu.addItem("RA", RA_Menu); lcdMenu.addItem("DEC", DEC_Menu); -#ifdef SUPPORT_POINTS_OF_INTEREST +#if SUPPORT_POINTS_OF_INTEREST == 1 lcdMenu.addItem("GO", POI_Menu); #else lcdMenu.addItem("GO", Home_Menu); @@ -104,19 +200,19 @@ void setup() { lcdMenu.addItem("HA", HA_Menu); -#ifdef SUPPORT_HEATING +#if SUPPORT_HEATING == 1 lcdMenu.addItem("HEA", Heat_Menu); #endif -#ifdef SUPPORT_MANUAL_CONTROL +#if SUPPORT_MANUAL_CONTROL == 1 lcdMenu.addItem("CTRL", Control_Menu); #endif -#ifdef SUPPORT_CALIBRATION +#if SUPPORT_CALIBRATION == 1 lcdMenu.addItem("CAL", Calibration_Menu); #endif -#ifdef SUPPORT_INFO_DISPLAY +#if SUPPORT_INFO_DISPLAY == 1 lcdMenu.addItem("INFO", Status_Menu); #endif @@ -127,8 +223,5 @@ void setup() { lcdMenu.updateDisplay(); #endif // HEADLESS_CLIENT -#ifdef DEBUG_MODE - Serial.println("Setup done!"); -#endif - + LOGV1(DEBUG_ANY, "Setup done!"); } diff --git a/Software/Arduino code/OpenAstroTracker/c65_startup.hpp b/Software/Arduino code/OpenAstroTracker/c65_startup.hpp index 37878b61..c6248ea9 100644 --- a/Software/Arduino code/OpenAstroTracker/c65_startup.hpp +++ b/Software/Arduino code/OpenAstroTracker/c65_startup.hpp @@ -1,7 +1,7 @@ #pragma once -#ifndef HEADLESS_CLIENT -#ifdef SUPPORT_GUIDED_STARTUP +#if HEADLESS_CLIENT == 0 +#if SUPPORT_GUIDED_STARTUP == 1 ////////////////////////////////////////////////////////////// // This file contains the Starup 'wizard' that guides you through initial setup diff --git a/Software/Arduino code/OpenAstroTracker/c70_menuRA.hpp b/Software/Arduino code/OpenAstroTracker/c70_menuRA.hpp index 6160ca4f..5446d8b1 100644 --- a/Software/Arduino code/OpenAstroTracker/c70_menuRA.hpp +++ b/Software/Arduino code/OpenAstroTracker/c70_menuRA.hpp @@ -1,6 +1,6 @@ #pragma once -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 bool processRAKeys() { byte key; bool waitForRelease = false; diff --git a/Software/Arduino code/OpenAstroTracker/c71_menuDEC.hpp b/Software/Arduino code/OpenAstroTracker/c71_menuDEC.hpp index 5504886b..a7612ba5 100644 --- a/Software/Arduino code/OpenAstroTracker/c71_menuDEC.hpp +++ b/Software/Arduino code/OpenAstroTracker/c71_menuDEC.hpp @@ -1,6 +1,6 @@ #pragma once -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 bool processDECKeys() { byte key; bool waitForRelease = false; diff --git a/Software/Arduino code/OpenAstroTracker/c722_menuPOI.hpp b/Software/Arduino code/OpenAstroTracker/c722_menuPOI.hpp index a6c1107a..05be0375 100644 --- a/Software/Arduino code/OpenAstroTracker/c722_menuPOI.hpp +++ b/Software/Arduino code/OpenAstroTracker/c722_menuPOI.hpp @@ -1,13 +1,13 @@ #pragma once -#ifndef HEADLESS_CLIENT -#ifdef SUPPORT_POINTS_OF_INTEREST +#if HEADLESS_CLIENT == 0 +#if SUPPORT_POINTS_OF_INTEREST == 1 struct PointOfInterest { - char* pDisplay; + const char* pDisplay; byte hourRA; byte minRA; byte secRA; - byte degreeDEC; + int degreeDEC; byte minDEC; byte secDEC; }; @@ -15,10 +15,10 @@ struct PointOfInterest { PointOfInterest pointOfInterest[] = { // Name (15chars) RA (hms) DEC (dms) // 012345678901234 - { ">Polaris" , PolarisRAHour, PolarisRAMinute, PolarisRASecond, 89, 21, 2 }, + { ">Polaris" , PolarisRAHour, PolarisRAMinute, PolarisRASecond, 89, 21, 6 }, { ">Big Dipper" , 12, 16, 26, 56, 55, 7 }, { ">M31 Andromeda" , 0, 43, 52, 41, 22, 53 }, - // { ">M42 Orion Nbula", 5, 36, 18, -5, 22, 44 }, // had to comment it out because -5 is not a valid byte (unsigned int8) value a real fix is on its way + { ">M42 Orion Nbula", 5, 36, 18, -5, 22, 44 }, { ">M51 Whirlpool" , 13, 30, 45, 47, 05, 21 }, { ">M63 Sunflower" , 13, 16, 45, 41, 55, 14 }, { ">M81 Bodes Galxy", 9, 57, 13, 68, 58, 1 }, diff --git a/Software/Arduino code/OpenAstroTracker/c725_menuHOME.hpp b/Software/Arduino code/OpenAstroTracker/c725_menuHOME.hpp index a39646b3..4040a811 100644 --- a/Software/Arduino code/OpenAstroTracker/c725_menuHOME.hpp +++ b/Software/Arduino code/OpenAstroTracker/c725_menuHOME.hpp @@ -1,6 +1,8 @@ #pragma once -#ifndef HEADLESS_CLIENT +#include "b_setup.hpp" + +#if HEADLESS_CLIENT == 0 byte subGoIndex = 0; bool processHomeKeys() { diff --git a/Software/Arduino code/OpenAstroTracker/c72_menuHA.hpp b/Software/Arduino code/OpenAstroTracker/c72_menuHA.hpp index 4066debb..86b4153c 100644 --- a/Software/Arduino code/OpenAstroTracker/c72_menuHA.hpp +++ b/Software/Arduino code/OpenAstroTracker/c72_menuHA.hpp @@ -1,6 +1,7 @@ #pragma once +#include "EPROMStore.hpp" -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 bool processHAKeys() { byte key; @@ -32,13 +33,13 @@ bool processHAKeys() { break; case btnSELECT: { - EEPROM.update(1, mount.HA().getHours()); - EEPROM.update(2, mount.HA().getMinutes()); + EPROMStore::Storage()->update(1, mount.HA().getHours()); + EPROMStore::Storage()->update(2, mount.HA().getMinutes()); lcdMenu.printMenu("Stored."); mount.delay(500); mount.setHome(); -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 if (startupState == StartupWaitForHACompletion) { startupState = StartupHAConfirmed; inStartup = true; @@ -48,7 +49,7 @@ bool processHAKeys() { break; case btnRIGHT: { -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 if (startupState != StartupWaitForHACompletion) #endif { diff --git a/Software/Arduino code/OpenAstroTracker/c74_menuHEAT.hpp b/Software/Arduino code/OpenAstroTracker/c74_menuHEAT.hpp index 8a4e9d97..0a0ec0c9 100644 --- a/Software/Arduino code/OpenAstroTracker/c74_menuHEAT.hpp +++ b/Software/Arduino code/OpenAstroTracker/c74_menuHEAT.hpp @@ -1,7 +1,7 @@ #pragma once -#ifndef HEADLESS_CLIENT -#ifdef SUPPORT_HEATING +#if HEADLESS_CLIENT == 0 +#if SUPPORT_HEATING == 1 bool processHeatKeys() { byte key; diff --git a/Software/Arduino code/OpenAstroTracker/c75_menuCTRL.hpp b/Software/Arduino code/OpenAstroTracker/c75_menuCTRL.hpp index 22ed13a4..80c8f651 100644 --- a/Software/Arduino code/OpenAstroTracker/c75_menuCTRL.hpp +++ b/Software/Arduino code/OpenAstroTracker/c75_menuCTRL.hpp @@ -1,7 +1,7 @@ #pragma once -#ifndef HEADLESS_CLIENT -#ifdef SUPPORT_MANUAL_CONTROL +#if HEADLESS_CLIENT == 0 +#if SUPPORT_MANUAL_CONTROL == 1 bool confirmZeroPoint = false; bool setZeroPoint = true; @@ -32,6 +32,8 @@ bool processKeyStateChanges(int key, int dir) loopsWithKeyPressed++; } } + + return ret; } bool processControlKeys() { @@ -59,20 +61,16 @@ bool processControlKeys() { if (key == btnSELECT) { if (setZeroPoint) { // Leaving Control Menu, so set stepper motor positions to zero. -#ifdef DEBUG_MODE - logv("Mount::CALC: Calling setHome()!"); -#endif + LOGV1(DEBUG_GENERAL, "CTRL menu: Calling setHome()!"); mount.setHome(); -#ifdef DEBUG_MODE - logv("Mount::CALC: setHome() returned: RA Current %s, Target: %f", mount.RAString(CURRENT_STRING|COMPACT_STRING).c_str(), mount.RAString(TARGET_STRING | COMPACT_STRING).c_str()); -#endif + LOGV3(DEBUG_GENERAL, "CTRL menu: setHome() returned: RA Current %s, Target: %f", mount.RAString(CURRENT_STRING|COMPACT_STRING).c_str(), mount.RAString(TARGET_STRING | COMPACT_STRING).c_str()); mount.startSlewing(TRACKING); } // Set flag to prevent resetting zero point when moving over the menu items inControlMode = false; -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 if (startupState == StartupWaitForPoleCompletion) { startupState = StartupPoleConfirmed; inStartup = true; diff --git a/Software/Arduino code/OpenAstroTracker/c76_menuCAL.hpp b/Software/Arduino code/OpenAstroTracker/c76_menuCAL.hpp index d60a3af2..37e372cc 100644 --- a/Software/Arduino code/OpenAstroTracker/c76_menuCAL.hpp +++ b/Software/Arduino code/OpenAstroTracker/c76_menuCAL.hpp @@ -1,8 +1,9 @@ #pragma once +#include "Globals.hpp" -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 -#ifdef SUPPORT_CALIBRATION +#if SUPPORT_CALIBRATION == 1 // HIGHLIGHT states allow you to pick one of the three sub functions. #define HIGHLIGHT_FIRST 1 @@ -12,15 +13,14 @@ #define HIGHLIGHT_RA_STEPS 4 #define HIGHLIGHT_DEC_STEPS 5 #define HIGHLIGHT_BACKLASH_STEPS 6 +// #define HIGHLIGHT_BACKLIGHT 7 #define HIGHLIGHT_LAST 6 // Polar calibration goes through these three states: -// 11- moving to RA of Polaris and then waiting on confirmation that Polaris is centered -// 12- moving to DEC beyond Polaris and waiting on confirmation that Polaris is centered +// 11- moving to RA and DEC beyond Polaris and waiting on confirmation that Polaris is centered // 13- moving back to home position -#define POLAR_CALIBRATION_WAIT 11 -#define POLAR_CALIBRATION_GO 12 -#define POLAR_CALIBRATION_WAIT_HOME 13 +#define POLAR_CALIBRATION_WAIT_CENTER_POLARIS 11 +#define POLAR_CALIBRATION_WAIT_HOME 12 // Speed calibration only has one state, allowing you to adjust the speed with UP and DOWN #define SPEED_CALIBRATION 14 @@ -41,10 +41,13 @@ // Backlash calibration only has one state, allowing you to adjust the number of steps with UP and DOWN #define BACKLASH_CALIBRATION 19 +// Brightness setting only has one state, allowing you to adjust the brightness with UP and DOWN +// #define BACKLIGHT_CALIBRATION 20 + // Start off with Polar Alignment higlighted. byte calState = HIGHLIGHT_FIRST; -// SPeed adjustment variable. Added to 1.0 after dividing by 10000 to get final speed +// Speed adjustment variable. Added to 1.0 after dividing by 10000 to get final speed float SpeedCalibration; // The current delay in ms when changing calibration value. The longer a button is depressed, the smaller this gets. @@ -59,6 +62,9 @@ byte driftDuration = 0; // The number of steps to use for backlash compensation (read from the mount). int BacklashSteps = 0; +// The brightness of the backlight of the LCD shield. +// int Brightness = 255; + bool checkProgressiveUpDown(int* val) { bool ret = true; @@ -77,6 +83,8 @@ bool checkProgressiveUpDown(int* val) { else { calDelay = 150; } + + return ret; } // Since the mount persists this in EEPROM and no longer in global @@ -97,6 +105,9 @@ void gotoNextHighlightState(int dir) { else if (calState == HIGHLIGHT_SPEED) { SpeedCalibration = (mount.getSpeedCalibration() - 1.0) * 10000.0 + 0.5; } + // else if (calState == HIGHLIGHT_BACKLIGHT) { + // Brightness = lcdMenu.getBacklightBrightness(); + // } } bool processCalibrationKeys() { @@ -139,8 +150,19 @@ bool processCalibrationKeys() { else if (calState == BACKLASH_CALIBRATION) { checkForKeyChange = checkProgressiveUpDown(&BacklashSteps); } + // else if (calState == BACKLIGHT_CALIBRATION) { + // checkForKeyChange = checkProgressiveUpDown(&Brightness); + // if (!checkForKeyChange) { + // LOGV2(DEBUG_INFO,"CAL: Brightness changed to %d", Brightness); + // Brightness = clamp(Brightness, 0, 255); + // LOGV2(DEBUG_INFO,"CAL: Brightness clamped to %d", Brightness); + // lcdMenu.setBacklightBrightness(Brightness, false); + // LOGV2(DEBUG_INFO,"CAL: Brightness set %d", (int)lcdMenu.getBacklightBrightness()); + // } + // } else if (calState == POLAR_CALIBRATION_WAIT_HOME) { if (!mount.isSlewingRAorDEC()) { + lcdMenu.updateDisplay(); calState = HIGHLIGHT_POLAR; } @@ -177,13 +199,9 @@ bool processCalibrationKeys() { switch (calState) { - case POLAR_CALIBRATION_GO: { + case POLAR_CALIBRATION_WAIT_HOME: { if (key == btnSELECT) { - lcdMenu.printMenu("Aligned, homing"); - mount.delay(600); - mount.setTargetToHome(); - mount.startSlewingToTarget(); - calState = POLAR_CALIBRATION_WAIT_HOME; + calState = HIGHLIGHT_POLAR; } if (key == btnRIGHT) { lcdMenu.setNextActive(); @@ -244,9 +262,7 @@ bool processCalibrationKeys() { { // UP and DOWN are handled above if (key == btnSELECT) { -#ifdef DEBUG_MODE - logv("CAL: Set backlash to %d", BacklashSteps); -#endif + LOGV2(DEBUG_GENERAL, "CAL Menu: Set backlash to %d", BacklashSteps); mount.setBacklashCorrection(BacklashSteps); lcdMenu.printMenu("Backlash stored."); mount.delay(500); @@ -259,18 +275,36 @@ bool processCalibrationKeys() { } break; + // case BACKLIGHT_CALIBRATION: + // { + // // UP and DOWN are handled above + // if (key == btnSELECT) { + // LOGV2(DEBUG_GENERAL, "CAL Menu: Set brightness to %d", Brightness); + // lcdMenu.setBacklightBrightness(Brightness); + // lcdMenu.printMenu("Level stored."); + // mount.delay(500); + // calState = HIGHLIGHT_BACKLIGHT; + // } + // else if (key == btnRIGHT) { + // lcdMenu.setNextActive(); + // calState = HIGHLIGHT_BACKLIGHT; + // } + // } + // break; + case HIGHLIGHT_POLAR: { if (key == btnDOWN) gotoNextHighlightState(1); else if (key == btnUP) gotoNextHighlightState(-1); else if (key == btnSELECT) { - calState = POLAR_CALIBRATION_WAIT; + calState = POLAR_CALIBRATION_WAIT_CENTER_POLARIS; // Move the RA to that of Polaris. Moving to this RA aligns the DEC axis such that // it swings along the line between Polaris and the Celestial Pole. mount.targetRA() = DayTime(PolarisRAHour, PolarisRAMinute, PolarisRASecond); - // Now set DEC to move to Home position - mount.targetDEC() = DegreeTime(90 - (NORTHERN_HEMISPHERE ? 90 : -90), 0, 0); + // Set DEC to move the same distance past Polaris as + // it is from the Celestial Pole. That equates to 88deg 42' 11.2". + mount.targetDEC() = DegreeTime(88 - (NORTHERN_HEMISPHERE ? 90 : -90), 42, 11); mount.startSlewingToTarget(); } else if (key == btnRIGHT) { @@ -279,14 +313,21 @@ bool processCalibrationKeys() { } break; - case POLAR_CALIBRATION_WAIT: { + case POLAR_CALIBRATION_WAIT_CENTER_POLARIS: { if (key == btnSELECT) { - calState = POLAR_CALIBRATION_GO; + calState = POLAR_CALIBRATION_WAIT_HOME; + lcdMenu.printMenu("Aligned, homing"); + mount.delay(750); - // RA is already set. Now set DEC to move the same distance past Polaris as - // it is from the Celestial Pole. That equates to 88deg 42' 6". - mount.targetDEC() = DegreeTime(89 - (NORTHERN_HEMISPHERE ? 90 : -90), 21, 3); + // Sync the mount to Polaris, since that's where it's pointing + DayTime currentRa = mount.currentRA(); + mount.syncPosition(currentRa.getHours(), currentRa.getMinutes(), currentRa.getSeconds(), 89 - (NORTHERN_HEMISPHERE ? 90 : -90), 21, 6); + + // Go home from here + mount.setTargetToHome(); mount.startSlewingToTarget(); + lcdMenu.setNextActive(); + calState = HIGHLIGHT_POLAR; } else if (key == btnRIGHT) { lcdMenu.setNextActive(); @@ -371,6 +412,16 @@ bool processCalibrationKeys() { } } break; + // case HIGHLIGHT_BACKLIGHT : { + // if (key == btnDOWN) gotoNextHighlightState(1); + // if (key == btnUP) gotoNextHighlightState(-1); + // else if (key == btnSELECT) calState = BACKLIGHT_CALIBRATION; + // else if (key == btnRIGHT) { + // lcdMenu.setNextActive(); + // calState = HIGHLIGHT_FIRST; + // } + // } + // break; } } @@ -398,7 +449,10 @@ void printCalibrationSubmenu() else if (calState == HIGHLIGHT_BACKLASH_STEPS) { lcdMenu.printMenu(">Backlash Adjust"); } - else if ((calState == POLAR_CALIBRATION_WAIT_HOME) || (calState == POLAR_CALIBRATION_WAIT) || (calState == POLAR_CALIBRATION_GO)) { + // else if (calState == HIGHLIGHT_BACKLIGHT) { + // lcdMenu.printMenu(">LCD Brightness"); + // } + else if (calState == POLAR_CALIBRATION_WAIT_CENTER_POLARIS) { if (!mount.isSlewingRAorDEC()) { lcdMenu.setCursor(0, 0); lcdMenu.printMenu("Centr on Polaris"); @@ -428,6 +482,10 @@ void printCalibrationSubmenu() sprintf(scratchBuffer, "Backlash: %d", BacklashSteps); lcdMenu.printMenu(scratchBuffer); } + // else if (calState == BACKLIGHT_CALIBRATION) { + // sprintf(scratchBuffer, "Brightness: %d", Brightness); + // lcdMenu.printMenu(scratchBuffer); + // } } #endif diff --git a/Software/Arduino code/OpenAstroTracker/c78_menuINFO.hpp b/Software/Arduino code/OpenAstroTracker/c78_menuINFO.hpp index 4eacf045..17c4cc15 100644 --- a/Software/Arduino code/OpenAstroTracker/c78_menuINFO.hpp +++ b/Software/Arduino code/OpenAstroTracker/c78_menuINFO.hpp @@ -1,8 +1,8 @@ #pragma once -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 -#ifdef SUPPORT_INFO_DISPLAY +#if SUPPORT_INFO_DISPLAY == 1 byte infoIndex = 0; byte maxInfoIndex = 4; byte subIndex = 0; diff --git a/Software/Arduino code/OpenAstroTracker/c_buttons.hpp b/Software/Arduino code/OpenAstroTracker/c_buttons.hpp index c56fecaf..051af5c5 100644 --- a/Software/Arduino code/OpenAstroTracker/c_buttons.hpp +++ b/Software/Arduino code/OpenAstroTracker/c_buttons.hpp @@ -1,26 +1,37 @@ #pragma once -#ifdef SUPPORT_SERIAL_CONTROL +#include +#include "b_setup.hpp" +#include "c65_startup.hpp" +#include "c70_menuRA.hpp" +#include "c71_menuDEC.hpp" +#include "c722_menuPOI.hpp" +#include "c72_menuHA.hpp" +#include "c75_menuCTRL.hpp" +#include "c76_menuCAL.hpp" +#include "c78_menuINFO.hpp" + +#if SUPPORT_SERIAL_CONTROL == 1 #include "f_serial.hpp" #endif void BTin(); -#ifndef HEADLESS_CLIENT +#if HEADLESS_CLIENT == 0 int loopsOfSameKey = 0; int lastLoopKey = -1; -#ifdef LCD_BUTTON_TEST +#if LCD_BUTTON_TEST == 1 byte lastKey = btnNONE; - #endif +byte lcd_key; + void loop() { - byte lcd_key; - int adc_key_in; -#ifdef LCD_BUTTON_TEST +#if LCD_BUTTON_TEST == 1 + int adc_key_in; lcdMenu.setCursor(0, 0); lcdMenu.printMenu("Key Diagnostic"); @@ -59,7 +70,7 @@ void loop() { lcdMenu.setCursor(0, 1); -#ifdef SUPPORT_SERIAL_CONTROL +#if SUPPORT_SERIAL_CONTROL == 1 if (inSerialControl) { if (lcdButtons.keyChanged(&lcd_key)) { if (lcd_key == btnSELECT) { @@ -79,7 +90,7 @@ void loop() { bool waitForButtonRelease = false; // Handle the keys -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 if (inStartup) { waitForButtonRelease = processStartupKeys(); } @@ -94,7 +105,7 @@ void loop() { case DEC_Menu: waitForButtonRelease = processDECKeys(); break; -#ifdef SUPPORT_POINTS_OF_INTEREST +#if SUPPORT_POINTS_OF_INTEREST == 1 case POI_Menu: waitForButtonRelease = processPOIKeys(); break; @@ -107,25 +118,25 @@ void loop() { case HA_Menu: waitForButtonRelease = processHAKeys(); break; -#ifdef SUPPORT_HEATING +#if SUPPORT_HEATING == 1 case Heat_Menu: waitForButtonRelease = processHeatKeys(); break; #endif -#ifdef SUPPORT_CALIBRATION +#if SUPPORT_CALIBRATION == 1 case Calibration_Menu: waitForButtonRelease = processCalibrationKeys(); break; #endif -#ifdef SUPPORT_MANUAL_CONTROL +#if SUPPORT_MANUAL_CONTROL == 1 case Control_Menu: waitForButtonRelease = processControlKeys(); break; #endif -#ifdef SUPPORT_INFO_DISPLAY +#if SUPPORT_INFO_DISPLAY == 1 case Status_Menu: waitForButtonRelease = processStatusKeys(); break; @@ -152,7 +163,7 @@ void loop() { // Input handled, do output lcdMenu.setCursor(0, 1); -#ifdef SUPPORT_GUIDED_STARTUP +#if SUPPORT_GUIDED_STARTUP == 1 if (inStartup) { printStartupMenu(); } @@ -169,7 +180,7 @@ void loop() { { printDECSubmenu(); } -#ifdef SUPPORT_POINTS_OF_INTEREST +#if SUPPORT_POINTS_OF_INTEREST == 1 else if (activeMenu == POI_Menu) { printPOISubmenu(); } @@ -181,23 +192,23 @@ void loop() { else if (activeMenu == HA_Menu) { printHASubmenu(); } -#ifdef SUPPORT_HEATING +#if SUPPORT_HEATING == 1 else if (activeMenu == Heat_Menu) { printHeatSubmenu(); } #endif -#ifdef SUPPORT_MANUAL_CONTROL +#if SUPPORT_MANUAL_CONTROL == 1 else if (activeMenu == Control_Menu) { printControlSubmenu(); } #endif -#ifdef SUPPORT_CALIBRATION +#if SUPPORT_CALIBRATION == 1 else if (activeMenu == Calibration_Menu) { printCalibrationSubmenu(); } #endif -#ifdef SUPPORT_INFO_DISPLAY +#if SUPPORT_INFO_DISPLAY == 1 else if (activeMenu == Status_Menu) { printStatusSubmenu(); } @@ -212,8 +223,10 @@ void loop() { #else void loop() { +#ifndef ESP32 serialLoop(); BTin(); +#endif } #endif diff --git a/Software/Arduino code/OpenAstroTracker/f_serial.hpp b/Software/Arduino code/OpenAstroTracker/f_serial.hpp index a1a14748..f3feb493 100644 --- a/Software/Arduino code/OpenAstroTracker/f_serial.hpp +++ b/Software/Arduino code/OpenAstroTracker/f_serial.hpp @@ -1,6 +1,8 @@ #pragma once -#ifdef SUPPORT_SERIAL_CONTROL +#include "b_setup.hpp" + +#if SUPPORT_SERIAL_CONTROL == 1 #include "MeadeCommandProcessor.hpp" void processSerialData(); @@ -12,7 +14,7 @@ void serialLoop() mount.loop(); mount.displayStepperPositionThrottled(); -#ifdef ESP8266 +#ifdef ESPBOARD processSerialData(); #endif @@ -23,7 +25,7 @@ void serialLoop() ////////////////////////////////////////////////// // Event that is triggered when the serial port receives data. -#ifndef ESP8266 +#ifndef ESPBOARD void serialEvent() { processSerialData(); } @@ -34,11 +36,14 @@ void processSerialData() { while (Serial.available() > 0) { String inCmd = Serial.readStringUntil('#'); + LOGV2(DEBUG_SERIAL, "Serial: Received: %s", inCmd.c_str()); - auto retVal = MeadeCommandProcessor::instance()->processCommand(inCmd); + String retVal = MeadeCommandProcessor::instance()->processCommand(inCmd); if (retVal != "") { + LOGV2(DEBUG_SERIAL,"Serial: Replied: %s", inCmd.c_str()); Serial.print(retVal); } + mount.loop(); } } diff --git a/Software/Arduino code/OpenAstroTracker/platformio.ini b/Software/Arduino code/OpenAstroTracker/platformio.ini index 3657f70a..977067bf 100644 --- a/Software/Arduino code/OpenAstroTracker/platformio.ini +++ b/Software/Arduino code/OpenAstroTracker/platformio.ini @@ -11,20 +11,26 @@ [platformio] src_dir = . -[env] -framework = arduino -lib_ldf_mode = chain+ +[common] lib_deps = SPI Serial - LiquidCrystal + 887 AccelStepper EEPROM - WiFi + Wire + +[env] +framework = arduino +lib_ldf_mode = chain+ +monitor_speed = 57600 +upload_speed = 115200 +lib_deps = ${common.lib_deps} [env:mega2560] platform = atmelavr -board = megaatmega2560 +board = atmega2560 +upload_protocol = wiring [env:uno] platform = atmelavr @@ -34,11 +40,13 @@ board = uno platform = espressif8266 board = esp12e lib_deps = - LiquidCrystal - AccelStepper - EEPROM + ${common.lib_deps} ESP8266WiFi [env:esp32] platform = espressif32 board = esp32dev +upload_speed = 921600 +lib_deps = + ${common.lib_deps} + WiFi diff --git a/Software/Arduino code/Sidereal.cpp b/Software/Arduino code/Sidereal.cpp new file mode 100644 index 00000000..35f9d527 --- /dev/null +++ b/Software/Arduino code/Sidereal.cpp @@ -0,0 +1,44 @@ +#include "Sidereal.hpp" + +// Constants for sidereal calculation +// Source: http://www.stargazing.net/kepler/altaz.html +#define C1 100.46 +#define C2 0.985647 +#define C3 15.0 +#define C4 -0.5125 +#define J2000 2000 + +static DayTime Sidereal::calculateByGPS(TinyGPSPlus* gps){ + DayTime timeUTC = DayTime(gps->time.hour(), gps->time.minute(), gps->time.second()); + int deltaJd = calculateDeltaJd(gps->date.year(), gps->date.month(), gps->date.day()); + double deltaJ = deltaJd + ((timeUTC.getTotalHours()) / 24.0); + return DayTime((float)(calculateTheta(deltaJ, gps->location.lng(), timeUTC.getTotalHours()) / 15.0)); +} + +static const double Sidereal::calculateTheta(double deltaJ, double longitude, float timeUTC){ + double theta = C1; + theta += C2 * deltaJ; + theta += C3 * timeUTC; + theta += C4; + theta += longitude; + return fmod(theta, 360.0); +} + +static const int Sidereal::calculateDeltaJd(int year, int month, int day){ + const int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + // Calculating days without leapdays + long int deltaJd = (year - J2000) * 365 + day; + for (int i=0; i < month - 1; i++){ + deltaJd += daysInMonth[i]; + } + + // Add leapdays + if (month <= 2){ + // Not counting current year if we have not passed february yet + year--; + } + deltaJd += year / 4 - year / 100 + year / 400; + deltaJd -= J2000 / 4 - J2000 / 100 + J2000 / 400; + return deltaJd; +} diff --git a/Software/Arduino code/Sidereal.hpp b/Software/Arduino code/Sidereal.hpp new file mode 100644 index 00000000..141d8dcf --- /dev/null +++ b/Software/Arduino code/Sidereal.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "DayTime.hpp" + + +class Sidereal +{ + public: + static DayTime calculateByGPS(TinyGPSPlus* gps); + + private: + static const double calculateTheta(double deltaJ, double longitude, float timeUTC); + static const int calculateDeltaJd(int year, int month, int day); +}; diff --git a/Software/OATMobile/OATCommunications/CommunicationHandlers/CommunicationHandlerFactory.cs b/Software/OATMobile/OATCommunications/CommunicationHandlers/CommunicationHandlerFactory.cs new file mode 100644 index 00000000..80ea5ef7 --- /dev/null +++ b/Software/OATMobile/OATCommunications/CommunicationHandlers/CommunicationHandlerFactory.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using OATCommunications.ClientAdapters; +using static OATCommunications.ClientAdapters.UdpClientAdapter; +using OATCommunications.CommunicationHandlers; +using System.Collections.ObjectModel; + +namespace OATCommunications.CommunicationHandlers +{ + public static class CommunicationHandlerFactory + { + static ObservableCollection _available = new ObservableCollection(); + public static void DiscoverDevices() + { + _available.Clear(); + //foreach (var port in SerialPort.GetPortNames()) + //{ + // _available.Add("Serial : " + port); + //} + + var searcher = new UdpClientAdapter("OAT", 4031); + searcher.ClientFound += OnWifiClientFound; + searcher.StartClientSearch(); + } + + private static void OnWifiClientFound(object sender, ClientFoundEventArgs e) + { + _available.Insert(0, $"WiFi : {e.Name} ({e.Address}:4030)"); + } + + public static ObservableCollection AvailableDevices { get { return _available; } } + + public static ICommunicationHandler ConnectToDevice(string device) + { + //if (device.StartsWith("Serial : ")) + //{ + // string comPort = device.Substring("Serial : ".Length); + // return new SerialCommunicationHandler(comPort); + //} + //else + if (device.StartsWith("WiFi : ")) + { + var parts = device.Split("()".ToCharArray()); + string ipAddress = parts[1]; + return new TcpCommunicationHandler(ipAddress); + } + + return null; + } + + } +} diff --git a/Software/OATMobile/OATCommunications/CommunicationHandlers/TcpCommunicationHandler.cs b/Software/OATMobile/OATCommunications/CommunicationHandlers/TcpCommunicationHandler.cs index 4610738c..62947ff6 100644 --- a/Software/OATMobile/OATCommunications/CommunicationHandlers/TcpCommunicationHandler.cs +++ b/Software/OATMobile/OATCommunications/CommunicationHandlers/TcpCommunicationHandler.cs @@ -1,4 +1,5 @@ -using System; +using OATCommunications.Utilities; +using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; @@ -15,6 +16,8 @@ public class TcpCommunicationHandler : ICommunicationHandler public TcpCommunicationHandler(string spec) { + Log.WriteLine($"COMMFACTORY: Creating Wifi handler at {spec} ..."); + string ip = string.Empty; string port = string.Empty; @@ -25,13 +28,16 @@ public TcpCommunicationHandler(string spec) { ip = spec.Substring(0, colon); port = spec.Substring(colon + 1); + + Log.WriteLine($"COMMFACTORY: Wifi handler will monitor at {ip}:{port} ..."); + _ip = IPAddress.Parse(ip); _port = int.Parse(port); _client = new TcpClient(); } - catch + catch (Exception ex) { - + Log.WriteLine($"COMMFACTORY: Failed to create TCP client. {ex.Message}"); } } } @@ -62,69 +68,82 @@ private async Task SendCommand(string command, ResponseType nee { if (_client == null) { + Log.WriteLine($"TCP: Configuration error, IP [{_ip}] or port [{_port}] is invalid."); return new CommandResponse(string.Empty, false, $"Configuration error, IP [{_ip}] or port [{_port}] is invalid."); } - if (!_client.Connected) + int attempt = 1; + var respString = String.Empty; + + while ((attempt < 4) && (_client != null)) { + Log.WriteLine("TCP: [{0}] Attempt {1} to send command.", command, attempt); + if (!_client.Connected) + { + try + { + _client = new TcpClient(); + _client.Connect(_ip, _port); + } + catch (Exception e) + { + Log.WriteLine("TCP: [{0}] Failed To connect or create client for command: {1}", command, e.Message); + return new CommandResponse("", false, $"Failed To Connect to Client: {e.Message}"); + } + } + + _client.ReceiveTimeout = 500; + _client.SendTimeout = 500; + + string error = String.Empty; + + var stream = _client.GetStream(); + var bytes = Encoding.ASCII.GetBytes(command); try { - _client = new TcpClient(); - _client.Connect(_ip, _port); + await stream.WriteAsync(bytes, 0, bytes.Length); + Log.WriteLine("TCP: [{0}] Sent command!", command); } catch (Exception e) { - Debug.WriteLine($"Failed To connect or create client: \n{e.Message}"); - return new CommandResponse("", false, $"Failed To Connect to Client: {e.Message}"); + Log.WriteLine("TCP: [{0}] Unable to write command to stream: {1}", command, e.Message); + return new CommandResponse("", false, $"Failed to send message: {e.Message}"); } - } - - _client.ReceiveTimeout = 250; - _client.SendTimeout = 250; - - string error = String.Empty; - - var stream = _client.GetStream(); - var bytes = Encoding.ASCII.GetBytes(command); - try - { - await stream.WriteAsync(bytes, 0, bytes.Length); - } - catch (Exception e) - { - Debug.WriteLine(e.Message); - return new CommandResponse("", false, $"Failed to send message: {e.Message}"); - } - Debug.WriteLine($"Sent {command}"); - - var respString = String.Empty; - - try - { - switch (needsResponse) + try { - case ResponseType.NoResponse: - break; - - case ResponseType.DigitResponse: - case ResponseType.FullResponse: - { - var response = new byte[256]; - var respCount = await stream.ReadAsync(response, 0, response.Length); - respString = Encoding.ASCII.GetString(response, 0, respCount).TrimEnd("#".ToCharArray()); - Debug.WriteLine($"Received {respString}"); - } - break; + switch (needsResponse) + { + case ResponseType.NoResponse: + attempt = 10; + Log.WriteLine("TCP: [{0}] No reply needed to command", command); + break; + + case ResponseType.DigitResponse: + case ResponseType.FullResponse: + { + Log.WriteLine("TCP: [{0}] Expecting a reply needed to command, waiting...", command); + var response = new byte[256]; + var respCount = await stream.ReadAsync(response, 0, response.Length); + respString = Encoding.ASCII.GetString(response, 0, respCount).TrimEnd("#".ToCharArray()); + Log.WriteLine("TCP: [{0}] Received reply to command -> [{1}]", command, respString); + attempt = 10; + } + break; + } + } + catch (Exception e) + { + Log.WriteLine("TCP: [{0}] Failed to read reply to command. {1} thrown", command, e.GetType().Name); + if (needsResponse != ResponseType.NoResponse) + { + respString = "0#"; + } } - } - catch (Exception e) - { - Debug.WriteLine(e.Message); - return new CommandResponse("", false, $"Failed to receive message: {e.Message}"); - } - stream.Close(); + stream.Close(); + attempt++; + } return new CommandResponse(respString); } @@ -141,6 +160,7 @@ public void Disconnect() { if (_client != null && _client.Connected) { + Log.WriteLine("TCP: Closing port."); _client.Close(); _client = null; } diff --git a/Software/OpenAstroTracker ASCOM/OATControl/ViewModels/Log.cs b/Software/OATMobile/OATCommunications/Log.cs similarity index 55% rename from Software/OpenAstroTracker ASCOM/OATControl/ViewModels/Log.cs rename to Software/OATMobile/OATCommunications/Log.cs index d64395a7..6f8cbcd3 100644 --- a/Software/OpenAstroTracker ASCOM/OATControl/ViewModels/Log.cs +++ b/Software/OATMobile/OATCommunications/Log.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -namespace OATControl.ViewModels +namespace OATCommunications.Utilities { public class Log { private static DateTime appStartTime = DateTime.UtcNow; private static object oLock = new object(); - private static string sPath = string.Format("{0}\\oat_{1}-{2}.log", Environment.GetFolderPath(Environment.SpecialFolder.Personal), DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"), Environment.UserName); + private static string sFolder; + private static string sPath; private static List lstBuffer = new List(); private static DateTime dtLastUpdate = DateTime.Now.AddSeconds(5.0); @@ -28,6 +30,31 @@ public static string Filename public static void Init(string sTitle) { + // Create our logfile folder in AppData/Roaming + sFolder = string.Format("{0}\\OpenAstroTracker", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)); + Directory.CreateDirectory(sFolder); + + // Create this session logfile + sPath = string.Format("{0}\\OATControl_{1}-{2}.log", sFolder, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"), Environment.UserName); + + // Find old logfiles and keep the latest 5 around. + var oldLogFiles = Directory.GetFiles(sFolder, "OATControl*.log").OrderByDescending(s => s).Skip(5).ToList(); + + // Probably should run this by the user.... for now they can jhust manually delete them + // oldLogFiles.AddRange(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "oat_*.log")); + + foreach (var logFile in oldLogFiles) + { + try + { + File.Delete(logFile); + } + catch + { + // Oh well.... + } + } + Log.WriteLine("*********************************"); Log.WriteLine(string.Format("* {0} *", sTitle.PadRight(28))); Log.WriteLine("*********************************"); @@ -41,7 +68,7 @@ private static string FormatMessage(string message, object[] args) var sb = new StringBuilder(message.Length + 64); TimeSpan elapsed = DateTime.UtcNow - Log.appStartTime; - sb.AppendFormat("[{0}] [{1}]: ", elapsed.ToString("hh\\:mm\\:ss\\.ffff"), Thread.CurrentThread.ManagedThreadId); + sb.AppendFormat("[{0}] [{1:00}]: ", elapsed.ToString("hh\\:mm\\:ss\\.fff"), Thread.CurrentThread.ManagedThreadId); if (args != null && args.Length > 0) { @@ -61,11 +88,11 @@ public static void WriteLine(string message, params object[] args) { lock (Log.oLock) { - File.AppendAllText(Log.sPath, string.Join("\r\n", Log.lstBuffer.ToArray()) + "\r\n"); + var lines = string.Join("\r\n", Log.lstBuffer.ToArray()) + "\r\n"; + File.AppendAllText(Log.sPath, lines); Log.lstBuffer.Clear(); } Log.dtLastUpdate = DateTime.UtcNow; - return; } string sLine = FormatMessage(message, args); @@ -73,6 +100,7 @@ public static void WriteLine(string message, params object[] args) lock (Log.oLock) { Log.lstBuffer.Add(sLine); + Debug.WriteLine(sLine); if (Log.lstBuffer.Count > Log.maxBuffered) { Log.maxBuffered = Log.lstBuffer.Count; @@ -82,6 +110,15 @@ public static void WriteLine(string message, params object[] args) public static void Quit() { + if (Log.lstBuffer.Any()) + { + lock (Log.oLock) + { + Log.lstBuffer.Add(Log.FormatMessage("Shutdown logging. Maximum of {0} lines buffered.", new Object[] { (object)Log.maxBuffered })); + File.AppendAllText(Log.sPath, string.Join("\r\n", Log.lstBuffer.ToArray()) + "\r\n"); + Log.lstBuffer.Clear(); + } + } } } } diff --git a/Software/OATMobile/OATMobile/OATMobile/App.xaml.cs b/Software/OATMobile/OATMobile/OATMobile/App.xaml.cs index c92f4a94..b4b48b26 100644 --- a/Software/OATMobile/OATMobile/OATMobile/App.xaml.cs +++ b/Software/OATMobile/OATMobile/OATMobile/App.xaml.cs @@ -2,6 +2,8 @@ using OATMobile.Services; using OATMobile.Views; +using OATCommunications.CommunicationHandlers; + namespace OATMobile { public partial class App : Application @@ -17,6 +19,7 @@ public App() protected override void OnStart() { + CommunicationHandlerFactory.DiscoverDevices(); } protected override void OnSleep() diff --git a/Software/OATMobile/OATMobile/OATMobile/ViewModels/MountControlViewModel.cs b/Software/OATMobile/OATMobile/OATMobile/ViewModels/MountControlViewModel.cs index 784e60ad..2ef627e3 100644 --- a/Software/OATMobile/OATMobile/OATMobile/ViewModels/MountControlViewModel.cs +++ b/Software/OATMobile/OATMobile/OATMobile/ViewModels/MountControlViewModel.cs @@ -3,56 +3,109 @@ using OATCommunications.TelescopeCommandHandlers; using Xamarin.Forms; using Xamarin.Essentials; +using System.Linq; +using OATCommunications; +using OATCommunications.CommunicationHandlers; +using System.Net; +using System.Timers; -namespace OATMobile.ViewModels { - public class MountControlViewModel : ViewModelBase { +namespace OATMobile.ViewModels +{ + public class MountControlViewModel : ViewModelBase + { + private ITelescopeCommandHandler _cmdHandler; - private ITelescopeCommandHandler _cmdHandler; + public string OppositeParkStateText { get; private set; } = "Unpark"; + private Timer discoveryTimer = new Timer(500); - public string OppositeParkStateText { get; private set; } = "Unpark"; + public MountControlViewModel() + { + Title = "Control"; - public MountControlViewModel(ITelescopeCommandHandler handler) { - _cmdHandler = handler; - Title = "Control"; + if (CommunicationHandlerFactory.AvailableDevices.Any()) + { + ConnectToDevice(); + } + else + { + discoveryTimer.Elapsed += (s, e) => + { + if (CommunicationHandlerFactory.AvailableDevices.Any()) + { + discoveryTimer.Stop(); - _cmdHandler.MountState.PropertyChanged += MountStateOnPropertyChanged; + // This is probably needed for Windows. Seems to work OK on Android. + // RunOnUiThread() is platform specific :-( - Commands.Add("GoHome", new Command(async () => { - await _cmdHandler.GoHome(); - await _cmdHandler.RefreshMountState(); - })); + //Activity.RunOnUiThread(() => + //{ + ConnectToDevice(); + discoveryTimer.Dispose(); + discoveryTimer = null; + //}); + } + }; - Commands.Add("StartMoveDirection", new Command(x => { _cmdHandler.StartMoving(x); })); + discoveryTimer.Start(); + } + } - Commands.Add("StopMoveDirection", new Command(x => { _cmdHandler.StopMoving(x); })); + public void ConnectToDevice() + { + var device = CommunicationHandlerFactory.ConnectToDevice(CommunicationHandlerFactory.AvailableDevices.First()); + _cmdHandler = new OatmealTelescopeCommandHandlers(device); - Commands.Add("SetTracking", new Command(x => { _cmdHandler.SetTracking(x); })); + _cmdHandler.MountState.PropertyChanged += MountStateOnPropertyChanged; - Commands.Add("SetLocation", new Command(async () => { - var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Default)); - await _cmdHandler.SetLocation(location.Latitude, location.Longitude, 0, 0); - })); + Commands.Add("GoHome", new Command(async () => + { + await _cmdHandler?.GoHome(); + await _cmdHandler?.RefreshMountState(); + })); - Commands.Add("ToggleParkedState", new Command(async () => { - if (_cmdHandler.MountState.IsTracking) { - await _cmdHandler.SetTracking(false); - } - else { - await _cmdHandler.SetTracking(true); - } - })); + Commands.Add("StartMoveDirection", new Command(x => { _cmdHandler?.StartMoving(x); })); - _cmdHandler.RefreshMountState(); - } + Commands.Add("StopMoveDirection", new Command(x => { _cmdHandler?.StopMoving(x); })); - private void MountStateOnPropertyChanged(object sender, PropertyChangedEventArgs e) { - switch (e.PropertyName) { - case nameof(MountState.IsTracking): - OppositeParkStateText = _cmdHandler.MountState.IsTracking ? "Park" : "Unpark"; - break; - } - } + Commands.Add("SetTracking", new Command(x => { _cmdHandler?.SetTracking(x); })); - public bool IsConnected { get; private set; } - } + Commands.Add("SetLocation", new Command(async () => + { + var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Default)); + await _cmdHandler?.SetLocation(location.Latitude, location.Longitude, 0, 0); + })); + + Commands.Add("ToggleParkedState", new Command(async () => + { + if (_cmdHandler != null) + { + if (_cmdHandler.MountState.IsTracking) + { + await _cmdHandler?.SetTracking(false); + } + else + { + await _cmdHandler?.SetTracking(true); + } + } + })); + + _cmdHandler?.RefreshMountState(); + } + + private void MountStateOnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (_cmdHandler != null) + { + switch (e.PropertyName) + { + case nameof(MountState.IsTracking): + OppositeParkStateText = _cmdHandler.MountState.IsTracking ? "Park" : "Unpark"; + break; + } + } + } + + public bool IsConnected { get; private set; } + } } \ No newline at end of file diff --git a/Software/OATMobile/OATMobile/OATMobile/Views/MountControlView.xaml.cs b/Software/OATMobile/OATMobile/OATMobile/Views/MountControlView.xaml.cs index 409fb8ba..2162e318 100644 --- a/Software/OATMobile/OATMobile/OATMobile/Views/MountControlView.xaml.cs +++ b/Software/OATMobile/OATMobile/OATMobile/Views/MountControlView.xaml.cs @@ -5,6 +5,7 @@ using OATCommunications.CommunicationHandlers; using Xamarin.Forms; using OATMobile.ViewModels; +using System.Linq; namespace OATMobile.Views { // Learn more about making custom code visible in the Xamarin.Forms previewer @@ -15,20 +16,23 @@ public partial class MountControlView : ContentPage { public MountControlView() { InitializeComponent(); - var handler = - new OatmealTelescopeCommandHandlers( - new TcpCommunicationHandler(new IPAddress(new byte[] {192, 168, 86, 57}), 4030)); - BindingContext = viewModel = new MountControlViewModel(handler); + BindingContext = viewModel = new MountControlViewModel(); } private void Move_Button_Pressed(object sender, EventArgs e) { var dir = (sender as ImageButton).CommandParameter.ToString(); - viewModel.Commands["StartMoveDirection"].Execute(dir); + if (viewModel.Commands.Any()) + { + viewModel.Commands["StartMoveDirection"].Execute(dir); + } } private void Move_Button_Released(object sender, EventArgs e) { var dir = (sender as ImageButton).CommandParameter.ToString(); - viewModel.Commands["StopMoveDirection"].Execute(dir); + if (viewModel.Commands.Any()) + { + viewModel.Commands["StopMoveDirection"].Execute(dir); + } } } } \ No newline at end of file diff --git a/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/CommunicationHandlerFactory.cs b/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/CommunicationHandlerFactory.cs index 9899c40c..a811477d 100644 --- a/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/CommunicationHandlerFactory.cs +++ b/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/CommunicationHandlerFactory.cs @@ -8,6 +8,7 @@ using OATCommunications.CommunicationHandlers; using System.Collections.ObjectModel; using OATCommuncations.WPF; +using OATCommunications.Utilities; namespace OATCommunications.WPF.CommunicationHandlers { @@ -16,12 +17,17 @@ public static class CommunicationHandlerFactory static ObservableCollection _available = new ObservableCollection(); public static void DiscoverDevices() { + Log.WriteLine("COMMFACTORY: Device Discovery initiated."); + Log.WriteLine("COMMFACTORY: Checking Serial ports...."); + _available.Clear(); foreach (var port in SerialPort.GetPortNames()) { + Log.WriteLine("COMMFACTORY: Found Serial port [{0}]", port); _available.Add("Serial : " + port); } + Log.WriteLine("COMMFACTORY: Starting Wifi search by Broadcastign OAT on port 4031"); var searcher = new UdpClientAdapter("OAT", 4031); searcher.ClientFound += OnWifiClientFound; searcher.StartClientSearch(); @@ -30,8 +36,8 @@ public static void DiscoverDevices() private static void OnWifiClientFound(object sender, ClientFoundEventArgs e) => WpfUtilities.RunOnUiThread( () => { + Log.WriteLine($"COMMFACTORY: Wifi device {e.Name} replied from {e.Address}:4030!"); _available.Insert(0, $"WiFi : {e.Name} ({e.Address}:4030)"); - }, System.Windows.Application.Current.Dispatcher); @@ -39,6 +45,7 @@ private static void OnWifiClientFound(object sender, ClientFoundEventArgs e) => public static ICommunicationHandler ConnectToDevice(string device) { + Log.WriteLine($"COMMFACTORY: Attempting to connect to device {device}..."); if (device.StartsWith("Serial : ")) { string comPort = device.Substring("Serial : ".Length); diff --git a/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/SerialCommunicationHandler.cs b/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/SerialCommunicationHandler.cs index 26f873f9..c9071ac9 100644 --- a/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/SerialCommunicationHandler.cs +++ b/Software/OpenAstroTracker ASCOM/OATCommuncations.WPF/CommunicationHandlers/SerialCommunicationHandler.cs @@ -1,4 +1,5 @@ using OATCommunications.CommunicationHandlers; +using OATCommunications.Utilities; using System; using System.Collections.Generic; using System.IO.Ports; @@ -15,6 +16,8 @@ public class SerialCommunicationHandler : ICommunicationHandler public SerialCommunicationHandler(string comPort) { + Log.WriteLine($"COMMFACTORY: Creating Serial handler on {comPort} at 57600 baud..."); + _portName = comPort; _port = new SerialPort(comPort); _port.BaudRate = 57600; @@ -46,11 +49,13 @@ private async Task SendCommand(string command, ResponseType nee { try { + Log.WriteLine("SERIAL: [{0}] Sending command", command); _port.Write(command); } - catch + catch (Exception ex) { - return new CommandResponse(string.Empty, false, $"Unable to write to {_portName}"); + Log.WriteLine("SERIAL: [{0}] Failed to send command. {1}", command, ex.Message); + return new CommandResponse(string.Empty, false, $"Unable to write to {_portName}. " + ex.Message); } try @@ -59,24 +64,30 @@ private async Task SendCommand(string command, ResponseType nee { case ResponseType.NoResponse: { + Log.WriteLine("SERIAL: [{0}] No response needed for command", command); return new CommandResponse(string.Empty, true); } case ResponseType.DigitResponse: { + Log.WriteLine("SERIAL: [{0}] Expecting single digit response for command, waiting...", command); string response = new string((char)_port.ReadChar(), 1); + Log.WriteLine("SERIAL: [{0}] Received single digit response '{1}' for command", command, response); return new CommandResponse(response, true); } case ResponseType.FullResponse: { + Log.WriteLine("SERIAL: [{0}] Expecting #-delimited response for Command, waiting...", command); string response = _port.ReadTo("#"); + Log.WriteLine("SERIAL: [{0}] Received response '{1}' for command", command, response); return new CommandResponse(response, true); } } } catch (Exception ex) { + Log.WriteLine("SERIAL: [{0}] Failed to receive response to command. {1}", command, ex.Message); return new CommandResponse(string.Empty, false, $"Unable to read response to {command} from {_portName}. {ex.Message}"); } @@ -84,6 +95,7 @@ private async Task SendCommand(string command, ResponseType nee } else { + Log.WriteLine("SERIAL: Failed to open port {0}", _portName); return new CommandResponse(string.Empty, false, $"Unable to open {_portName}"); } } @@ -94,13 +106,16 @@ private async Task EnsurePortIsOpen() { try { + Log.WriteLine("SERIAL: Port {0} is not open, attempting to open...", _portName); _port.Open(); await Task.Delay(750); // Arduino resets on connection. Give it time to start up. + Log.WriteLine("SERIAL: Port is open, sending initial [:I#] command.."); _port.Write(":I#"); return true; } - catch + catch (Exception ex) { + Log.WriteLine("SERIAL: Failed to open the port. {0}", ex.Message); return false; } } @@ -111,10 +126,13 @@ public void Disconnect() { if (_port.IsOpen) { + Log.WriteLine("SERIAL: Port is open, sending shutdown command [:Qq#]"); + _port.Write(":Qq#"); + Log.WriteLine("SERIAL: Closing port..."); _port.Close(); _port = null; + Log.WriteLine("SERIAL: Disconnected..."); } } - } } diff --git a/Software/OpenAstroTracker ASCOM/OATControl/App.xaml.cs b/Software/OpenAstroTracker ASCOM/OATControl/App.xaml.cs index 7fb35325..39cc915e 100644 --- a/Software/OpenAstroTracker ASCOM/OATControl/App.xaml.cs +++ b/Software/OpenAstroTracker ASCOM/OATControl/App.xaml.cs @@ -1,5 +1,4 @@ using MahApps.Metro; -using OATControl.ViewModels; using System; using System.Collections.Generic; using System.Configuration; @@ -7,7 +6,7 @@ using System.Linq; using System.Threading.Tasks; using System.Windows; - +using OATCommunications.Utilities; namespace OATControl { /// @@ -16,23 +15,30 @@ namespace OATControl public partial class App : Application { - protected override void OnStartup(StartupEventArgs e) - { - ThemeManager.AddAccent("RedAccent", new Uri("pack://application:,,,/OATControl;component/Resources/RedAccent.xaml")); - ThemeManager.AddAppTheme("RedTheme", new Uri("pack://application:,,,/OATControl;component/Resources/RedTheme.xaml")); - ThemeManager.AddAccent("RedControls", new Uri("pack://application:,,,/OATControl;component/Resources/RedControls.xaml")); + protected override void OnStartup(StartupEventArgs e) + { + ThemeManager.AddAccent("RedAccent", new Uri("pack://application:,,,/OATControl;component/Resources/RedAccent.xaml")); + ThemeManager.AddAppTheme("RedTheme", new Uri("pack://application:,,,/OATControl;component/Resources/RedTheme.xaml")); + ThemeManager.AddAccent("RedControls", new Uri("pack://application:,,,/OATControl;component/Resources/RedControls.xaml")); + + // get the current app style (theme and accent) from the application + // you can then use the current theme and custom accent instead set a new theme + Tuple appStyle = ThemeManager.DetectAppStyle(Application.Current); + + // now set the Green accent and dark theme + ThemeManager.ChangeAppStyle(Application.Current, + ThemeManager.GetAccent("RedAccent"), + ThemeManager.GetAppTheme("RedTheme")); - // get the current app style (theme and accent) from the application - // you can then use the current theme and custom accent instead set a new theme - Tuple appStyle = ThemeManager.DetectAppStyle(Application.Current); + Log.Init("OatControl"); + base.OnStartup(e); + } - // now set the Green accent and dark theme - ThemeManager.ChangeAppStyle(Application.Current, - ThemeManager.GetAccent("RedAccent"), - ThemeManager.GetAppTheme("RedTheme")); + protected override void OnExit(ExitEventArgs e) + { + Log.Quit(); - Log.Init("OatControl"); - base.OnStartup(e); - } - } + base.OnExit(e); + } + } } diff --git a/Software/OpenAstroTracker ASCOM/OATControl/Controls/InlineSlider.xaml b/Software/OpenAstroTracker ASCOM/OATControl/Controls/InlineSlider.xaml deleted file mode 100644 index 4e3c8796..00000000 --- a/Software/OpenAstroTracker ASCOM/OATControl/Controls/InlineSlider.xaml +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -