kopia lustrzana https://github.com/ozarchie/EQMOD-ETX
rodzic
a7471b0470
commit
2164dd2e5f
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 10 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 30 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 31 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 28 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 31 KiB |
|
@ -0,0 +1,11 @@
|
|||
<form onSubmit="sendForm(); return false;">
|
||||
<input type="image" src="images/eqmodwifi.gif" width="72" height="48">
|
||||
<font size="5" face="verdana"> EQG2HBX Settings</font><br><br>
|
||||
<label class="label">Network : </label>
|
||||
<input type="text" name="ssid" placeholder="EQGWiFi"><br>
|
||||
<label>Password : </label>
|
||||
<input type="text" name="pass" placeholder="EQG .. l"><br>
|
||||
<label>Telescope: </label>
|
||||
<input type="text" name="scope" placeholder="ETX60"><br>
|
||||
<input type="submit" value="Update">
|
||||
</form>
|
|
@ -0,0 +1,3 @@
|
|||
<form method='POST' action='/update' enctype='multipart/form-data'>\
|
||||
<input type='file' name='update'>\
|
||||
<input type='submit' value='Update'></form>
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
|
@ -0,0 +1,19 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:wemos_d1_mini32]
|
||||
platform = espressif32
|
||||
board = wemos_d1_mini32
|
||||
framework = arduino
|
||||
lib_deps = bertmelis/Ticker-esp32@^1.1.0
|
||||
lib_ldf_mode = deep
|
||||
monitor_speed = 115200
|
||||
monitor_filters = log2file, default, time, esp32_exception_decoder
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG2HBX program definitions
|
||||
===========================
|
||||
*********************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FS.h> // Include the SPIFFS library
|
||||
#include <Preferences.h>
|
||||
#include "ESP32Ticker.h"
|
||||
|
||||
void CheckETXState( unsigned char );
|
||||
|
||||
/**************************************************************
|
||||
* Common variables
|
||||
**************************************************************/
|
||||
String EQ2HBX_Version = "EQG2HBX V1.11";
|
||||
|
||||
Preferences preferences;
|
||||
unsigned long DelayTime; // Delay timer
|
||||
unsigned long StatusTime; // H2X interval time
|
||||
|
||||
unsigned long StatusTimer; // H2X status delay timer
|
||||
unsigned long StateTimer; // H2X state delay timer
|
||||
bool StateSelect;
|
||||
bool StatusSelect;
|
||||
int StatusCount;
|
||||
|
||||
Ticker AlarmCheckETX;
|
||||
|
||||
long P1;
|
||||
long P2;
|
||||
float F1;
|
||||
float F2;
|
||||
|
||||
time_t epoch; // UTC seconds
|
||||
time_t currentTime; // Local value
|
||||
|
||||
/**************************************************************
|
||||
* EQG protocol communications buffers and pointers
|
||||
* EQG protocol variables
|
||||
**************************************************************/
|
||||
|
||||
#define EQGLEN 256 // Communications buffers
|
||||
#define EQGMASK EQGLEN-1 // Index wraps to 0
|
||||
|
||||
unsigned long EQGP1;
|
||||
unsigned long EQGP2;
|
||||
float EQGF1;
|
||||
|
||||
unsigned char EQGRxBuffer[EQGLEN]; // Hold data from EQG
|
||||
unsigned char EQGTxBuffer[EQGLEN]; // Hold responses to EQG
|
||||
unsigned char EQGRxiPtr = 0; // Pointer for input from EQG
|
||||
unsigned char EQGRxoPtr = 0; // Pointer for output from EQG Rx buffer
|
||||
unsigned char EQGTxiPtr = 0; // Pointer for input to EQG buffer
|
||||
unsigned char EQGTxoPtr = 0; // Pointer for output to EQG
|
||||
|
||||
unsigned char EQGCmnd = 0; // EQG Command
|
||||
unsigned char EQGErrorValue; // EQG Returned error value
|
||||
unsigned char EQGDone = 0; // EQG Complete message
|
||||
unsigned char EQGRADEC = 0; // EQG Motor Select (ASCII)
|
||||
unsigned char EQGMOTOR = 0; // EQG Motor Select (binary)
|
||||
unsigned char EQGRAAutoguide = 0; // EQG Autoguide rate
|
||||
unsigned char EQGDECAutoguide = 0; // EQG Autoguide rate
|
||||
unsigned char EQGRxState = 1; // EQG State
|
||||
unsigned char EQGRxChar; // EQG Rx Character
|
||||
unsigned char EQGRxCount; // EQG # parameters
|
||||
float f;
|
||||
unsigned long v;
|
||||
|
||||
/**************************************************************
|
||||
* HBX communications buffers and pointers
|
||||
* HBX variables
|
||||
**************************************************************/
|
||||
|
||||
unsigned long H2XStart = 0; // Used to count uS ticks
|
||||
unsigned long H2XTimer = 0; // Used to count uS ticks
|
||||
unsigned char EQGMotorStatus; // Current State of motor
|
||||
|
||||
typedef struct {
|
||||
unsigned char MotorType; // Current type of motor
|
||||
unsigned char MotorFlag; // Flag to print motor positions
|
||||
|
||||
unsigned long ETXMotorState; // ETX Motor State Nachine
|
||||
unsigned long ETXMotorStatus; // Current ETX Motor Status
|
||||
unsigned long EQGMotorStatus; // Current EQG Motor Status
|
||||
unsigned long MotorControl; // Current HBX Motor Control bits
|
||||
|
||||
unsigned char HBXBitCount; // #bits left to process
|
||||
unsigned char Command; // Current command
|
||||
unsigned char Flip; // Axis flipped - Alt for negative, Az probably never
|
||||
unsigned char HBXData; // Data byte from HBX Bus
|
||||
unsigned char HBXP1; // HBX status/data - MSB
|
||||
unsigned char HBXP2; // HBX status/data - LSB
|
||||
unsigned char HBXP3; // HBX status/data - PWM % related
|
||||
unsigned char HBXP4; // HBX status/data - single flag bit related to battery alarm ( 0 = OK )
|
||||
unsigned char HBXCount; // HBX valid data count
|
||||
unsigned char HBXLEDI; // LED current value from Motor
|
||||
unsigned long DirnSpeed; // Speed, Direction for Motor to move
|
||||
char HBXGuide; // Guide speed
|
||||
char HBXSnapPort; // Snap port
|
||||
char LEDValue; // Polar LED brightness
|
||||
char ETXSpeedCommand; // Current ETX Speed command
|
||||
long EQGSpeed; // EQG Move speed
|
||||
long ETXSpeed; // ETX Move speed
|
||||
long TargetSpeed; // Target Move speed
|
||||
uint8_t SpeedState; // Slowdown/speedup state
|
||||
long Position; // Current position
|
||||
long Target; // Current target
|
||||
long Increment; // Change in position for motor speed calcs
|
||||
long SlowDown; // Point to change to lower speed
|
||||
long Offset; // Current adjustment
|
||||
|
||||
// MeadeRatio = ((Vanes * 4) * GbxRatio * XferRatio * WormTeeth) / 1,296,000
|
||||
float MeadeRatio; // Meade Ratio
|
||||
float GbxRatio; // GearBox Ratio
|
||||
unsigned long Vanes; // Number of photocoupler vanes
|
||||
float XferRatio; // Gearbox Transfer Ratio (usually 1)
|
||||
unsigned long WormTeeth; // Number of Worm teeth
|
||||
|
||||
// a-Value = (Vanes * 4) * GbxRatio * XferRatio * WormTeeth
|
||||
// b-Value = (6460.09 * MeadeRatio * a-Value * 15.041069) / 1,296,000
|
||||
unsigned long aVALUE; // For rate calculations
|
||||
unsigned long bVALUE; // For rate calculations
|
||||
unsigned long OneDegree; // For slew comparisons
|
||||
|
||||
// SIDEREALRATE = 6460.09 * MeadeRatio
|
||||
// SOLARRATE = (SOLARSECS/SIDEREALSECS) * SIDEREALRATE
|
||||
// LUNARRATE = (SOLARSECS/SIDEREALSECS) * SIDEREALRATE
|
||||
// DEGREERATE1 = SLEW7(240) * SIDEREALRATE
|
||||
// BASERATE = (b * arcsec360) / a
|
||||
|
||||
unsigned long SIDEREALRATE; // Constants
|
||||
unsigned long SOLARRATE;
|
||||
unsigned long LUNARRATE;
|
||||
unsigned long BASERATE;
|
||||
unsigned long DEGREERATE1;
|
||||
|
||||
// PEC = a-VALUE / WormTeeth;
|
||||
unsigned long PEC; // PEC period (period of worm tooth)
|
||||
|
||||
unsigned char PrintStatus0; // Force print of no status change
|
||||
unsigned long TimeDelta; // Used in HBX Monitor
|
||||
} axis_type;
|
||||
|
||||
axis_type axis[4]; // Az, Alt
|
||||
|
||||
// Support other scopes with Meade interface
|
||||
typedef struct {
|
||||
unsigned long Vanes; // Number of photocoupler vanes
|
||||
float GbxRatio; // GearBox Ratio
|
||||
float XferRatio; // Gearbox Transfer Ratio (usually 1)
|
||||
unsigned long WormTeeth; // Number of Worm teeth
|
||||
char Telescope[16]; // name of scope
|
||||
} axis_values;
|
||||
|
||||
axis_values ratio[16][2] = // 16 scopes, Az, Alt
|
||||
{
|
||||
{{36, 91.1458333, 1, 94, "ETX60"}, {36, 157.5, 1, 58, "ETX60"}}, // ETX60/70/80
|
||||
{{36, 91.1458333, 1, 94, "ETX70"}, {36, 157.5, 1, 58, "ETX70"}}, // ETX60/70/80
|
||||
{{36, 91.1458333, 1, 94, "ETX80"}, {36, 157.5, 1, 58, "ETX80"}}, // ETX60/70/80
|
||||
{{108, 50, 1, 144, "LXD55"}, {108, 50, 1, 144, "LXD55"}}, // LXD55/75, LX70-GTS
|
||||
{{108, 50, 1, 144, "LXD75"}, {108, 50, 1, 144, "LXD75"}}, // LXD55/75, LX70-GTS
|
||||
{{108, 50, 1, 144, "LXD70"}, {108, 50, 1, 144, "LXD70"}}, // LXD55/75, LX70-GTS
|
||||
{{108, 53.5859375, 1, 154, "LX90"}, {108, 53.5859375, 1, 154, "LX90"}}, // LX90, LT, LX80AltAz
|
||||
{{108, 53.5859375, 1, 154, "LT"}, {108, 53.5859375, 1, 154, "LT"}}, // LX90, LT, LX80AltAz
|
||||
{{108, 53.5859375, 1, 154, "LX80"}, {108, 53.5859375, 1, 154, "LX80"}}, // LX90, LT, LX80AltAz
|
||||
{{256, 50, 1, 350, "LX200"}, {256, 50, 1, 350, "LX200"}}, // LX200
|
||||
{{500, 36, 1, 225, "LX850"}, {500, 36, 1, 225, "LX850"}}, // LX850
|
||||
{{256, 50, 1, 180, "LX400"}, {256, 50, 1, 180, "LX400"}}, // LX400/500
|
||||
{{36, 205.3330000, 1, 144, "DSEXT"}, {36, 205.3330000, 1, 144, "DSEXT"}}, // DS external
|
||||
{{36, 410.6660000, 1, 100, "DHEXT"}, {36, 157.5, 1, 58, "DHEXT"}}, // DH external/114EQs/4504s
|
||||
|
||||
{{36, 205.3330000, 1, 60, "ETXnn"}, {36, 205.3330000, 1, 60, "ETXnn"}}, // ETX-xxx, DS-xxx
|
||||
{{36, 91.1458333, 1, 83, "ETX??"}, {36, 144.7362076, 1, 66, "ETX??"}} // ??
|
||||
};
|
||||
|
||||
unsigned char telescope = 0; // Default telescope (ETX60)
|
||||
unsigned char protocol = 0; // Default protocol (UDP)
|
||||
unsigned char station = 0; // Default station (AP)
|
||||
char scope[16] = "ETX60";
|
||||
|
||||
char* an0 = (char*)"Bad";
|
||||
char* an1 = (char*)"Az ";
|
||||
char* an2 = (char*)"Alt";
|
||||
char * axis_name[3] = { an0, an1, an2 };
|
||||
|
||||
char SpeedStateDesc[4][16] = {"ChangeToStep", "Slowing1", "Slowing2", "Stopped"};
|
||||
|
||||
|
||||
// Testing only
|
||||
|
||||
Ticker AlarmDebugPrint;
|
||||
#define dbgLEN 256 // Communications buffers
|
||||
#define dbgMASK dbgLEN-1 // Index wraps to 0
|
||||
unsigned char dbgRxBuffer[dbgLEN]; // Hold data from EQG
|
||||
char dbgCommand[dbgLEN]; // Hold data from EQG
|
||||
unsigned char dbgRxiPtr = 0; // Pointer for input from EQG
|
||||
unsigned char dbgRxoPtr = 0; // Pointer for output from EQG Rx buffer
|
||||
unsigned char dbgFlag = 0; // Received a command
|
||||
unsigned char dbgIndex = 0; // Index into command
|
||||
|
||||
unsigned char TestCount;
|
||||
unsigned long TestLoopTime;
|
||||
unsigned long PreviousTime; // Used in HBX Monitor, Testing
|
|
@ -0,0 +1,256 @@
|
|||
/**@file*/
|
||||
/*
|
||||
Name: EQG2HBXE32.ino
|
||||
Created: 2018-09-01 10:07:17 AM
|
||||
Author: JOHNWIN10PRO\John
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#include <dummy.h>
|
||||
#include "Hardware.h"
|
||||
|
||||
#include <FS.h> // Include the SPIFFS library
|
||||
#include <Preferences.h>
|
||||
#include "ESP32Ticker.h"
|
||||
//#include <BluetoothSerial.h>
|
||||
|
||||
#include "EQG2HBX.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
#include "HBXFileSystem.h"
|
||||
|
||||
|
||||
// Functions
|
||||
//
|
||||
/**************************************************************************************************
|
||||
* Read / Update ETX - Timer Driven
|
||||
**************************************************************************************************/
|
||||
void UpdateETX(void) {
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Get ETXStatus
|
||||
**************************************************************************************************/
|
||||
void CheckETXStatus(unsigned char Motor) {
|
||||
HBXGetStatus(Motor);
|
||||
}
|
||||
|
||||
/**************************************************************************************************
|
||||
* Check ETXState
|
||||
**************************************************************************************************/
|
||||
void CheckETXState(unsigned char Motor) {
|
||||
ETXState(Motor); // Check the motor state
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
Initialize HBX, translate EQG to HBX
|
||||
====================================
|
||||
*********************************************************/
|
||||
|
||||
// =======================================================================================================
|
||||
void setup()
|
||||
{
|
||||
// int i, j, k;
|
||||
// bool b;
|
||||
|
||||
#ifdef mESP32
|
||||
dbgSerial.begin(115200); // debug
|
||||
EQGSerial.begin(9600, SERIAL_8N1, 18, 19); // EQG via serial, bluetooth or WiFi
|
||||
#ifdef BTSerial
|
||||
EQGBluetooth.begin("EQ6Blue");
|
||||
#endif
|
||||
delay(10);
|
||||
#endif
|
||||
|
||||
dbgSerial.println(EQ2HBX_Version);
|
||||
DelayTime = micros(); // Initialize timers, counts
|
||||
StatusTime = DelayTime;
|
||||
EQGErrorValue = 0;
|
||||
|
||||
#ifdef mESP32
|
||||
HBXWiFiSetup();
|
||||
#endif
|
||||
|
||||
pinMode(ETXLED, OUTPUT); // Operation indicators
|
||||
pinMode(EQGLED, OUTPUT);
|
||||
digitalWrite(ETXLED, LOW);
|
||||
digitalWrite(EQGLED, LOW);
|
||||
|
||||
axis[AzMotor].PrintStatus0 = 0; // Disable printing "status polls" with no change
|
||||
axis[AltMotor].PrintStatus0 = 0; // Disable printing "status polls" with no change
|
||||
|
||||
// Initialize EQG communications
|
||||
dbgSerial.println("HBX Initialization");
|
||||
|
||||
// Read Motor Type to determine telescope type
|
||||
// -------------------------------------------
|
||||
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
|
||||
telescope = 0; // Default ETX60
|
||||
if (!(preferences.getUChar("TELESCOPE", 0) == 0)) { // If it exists check telescope table for a match
|
||||
telescope = (preferences.getUChar("TELESCOPE", 0));
|
||||
}
|
||||
dbgSerial.print("Telescope: ");
|
||||
dbgSerial.print(telescope);
|
||||
dbgSerial.print(", ");
|
||||
dbgSerial.println(ratio[telescope][0].Telescope);
|
||||
if (!(preferences.getUChar("PROTOCOL", 0) == 0)) { // If it exists get protocol type (UDP, NOW)
|
||||
protocol = (preferences.getUChar("PROTOCOL", 0));
|
||||
}
|
||||
dbgSerial.print("Protocol: ");
|
||||
dbgSerial.print(protocol);
|
||||
dbgSerial.print(", ");
|
||||
if (!(preferences.getUChar("STATION", 0) == 0)) { // If it exists get station type (AP, STA)
|
||||
protocol = (preferences.getUChar("STATION", 0));
|
||||
}
|
||||
dbgSerial.print("Station: ");
|
||||
dbgSerial.println(station);
|
||||
preferences.end();
|
||||
|
||||
AzInitialise(telescope);
|
||||
AltInitialise(telescope);
|
||||
//PrintRatioValues(telescope);
|
||||
PrintHbxValues(AzMotor);
|
||||
PrintHbxValues(AltMotor);
|
||||
|
||||
// Initialize HBX communications as outputs
|
||||
// It will use H2X communications
|
||||
HBXReset();
|
||||
|
||||
// Reset the motors (RA and DEC)
|
||||
// and wait until both respond to a command
|
||||
dbgSerial.println("Waiting for both motors to start up ..");
|
||||
WaitForMotors();
|
||||
|
||||
// Get Motor Type from Az MC ( assume both same type of motor)
|
||||
|
||||
do {
|
||||
axis[AzMotor].MotorType = 0x00;
|
||||
if (HBXSendCommand(GetMotorType, AzMotor))
|
||||
axis[AzMotor].MotorType = HBXGetByte(AzMotor);
|
||||
} while (!axis[AzMotor].MotorType);
|
||||
axis[AltMotor].MotorType = axis[AzMotor].MotorType;
|
||||
dbgSerial.println(""); dbgSerial.print("Motor Type: "); dbgSerial.print(axis[AltMotor].MotorType);
|
||||
|
||||
// Handle position sensors LED current
|
||||
// -----------------------------------
|
||||
dbgSerial.println(""); dbgSerial.print("Check Calibrate LEDs");
|
||||
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
|
||||
if (preferences.getUChar("AzLEDI", 0) == 0) { // If it does not exist, calibrate the LEDs
|
||||
CalibrateLEDs();
|
||||
}
|
||||
// Read stored LED currents
|
||||
axis[AzMotor].HBXLEDI = preferences.getUChar("AzLEDI", 0);
|
||||
axis[AltMotor].HBXLEDI = preferences.getUChar("AltLEDI", 0);
|
||||
preferences.end();
|
||||
|
||||
// Set the MC LED values
|
||||
dbgSerial.println(""); dbgSerial.print("Set MC LED values");
|
||||
if (HBXSendCommand(SetLEDI, AzMotor))
|
||||
HBXSendByte(axis[AzMotor].HBXLEDI, AzMotor);
|
||||
axis[AzMotor].HBXP1 = axis[AzMotor].HBXLEDI;
|
||||
HBXPrintStatus(AzMotor);
|
||||
|
||||
if (HBXSendCommand(SetLEDI, AltMotor))
|
||||
HBXSendByte(axis[AltMotor].HBXLEDI, AltMotor);
|
||||
axis[AltMotor].HBXP1 = axis[AltMotor].HBXLEDI;
|
||||
HBXPrintStatus(AltMotor);
|
||||
|
||||
// Set the Offset Clear Command
|
||||
// Send HBXP1, HBXP2
|
||||
dbgSerial.println(""); dbgSerial.print("Reset any ETX offset bytes");
|
||||
axis[AzMotor].HBXP1 = 0;
|
||||
axis[AzMotor].HBXP2 = 0;
|
||||
axis[AltMotor].HBXP1 = 0;
|
||||
axis[AltMotor].HBXP2 = 0;
|
||||
if (HBXSendCommand(SetOffset, AzMotor))
|
||||
HBXSend2Bytes(AzMotor);
|
||||
TimerDelaymS(CMNDTIME);
|
||||
if (HBXSendCommand(SetOffset, AltMotor))
|
||||
HBXSend2Bytes(AltMotor);
|
||||
TimerDelaymS(CMNDTIME);
|
||||
|
||||
// Stop the motors (RA and DEC)
|
||||
dbgSerial.println(""); dbgSerial.print("Stop motors");
|
||||
do {
|
||||
P1 = 0;
|
||||
if (HBXSendCommand(Stop, AzMotor)) P1 += 1;
|
||||
if (HBXSendCommand(Stop, AltMotor)) P1 += 1;
|
||||
} while (P1 < 2);
|
||||
|
||||
// Read status
|
||||
dbgSerial.println(""); dbgSerial.println("Read Status");
|
||||
HBXGet2Status(); // Check and read both motor states
|
||||
|
||||
dbgSerial.println("Setup Complete. Listening for commands ..");
|
||||
|
||||
// Print debug info every 10 s
|
||||
// ---------------------------
|
||||
|
||||
// HBXTestLoop();
|
||||
|
||||
// AlarmDebugPrint.attach(10, debugEQG); // Print debug info every 10 s
|
||||
// AlarmCheckETX.attach_ms(6, CheckETXState); // Check motor status (position), every 6mS
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================================================
|
||||
void loop()
|
||||
{
|
||||
/**************************************************************************************************
|
||||
* Process EQG comms - Rx, Tx Comms are interrupt driven
|
||||
**************************************************************************************************/
|
||||
|
||||
// dbgRx(); // Check for comms from debug port for telescope values
|
||||
|
||||
// Check ETX motor status and state
|
||||
if ((micros() - StateTimer) > (STATEDELAY * 1000)) { // ~6.55mS
|
||||
if (StateSelect) StateSelect = false;
|
||||
else StateSelect = true;
|
||||
StateTimer = micros();
|
||||
if (StateSelect) CheckETXState(AzMotor);
|
||||
else CheckETXState(AltMotor);
|
||||
}
|
||||
|
||||
//jma CheckAltFlipReqd();
|
||||
|
||||
if ((micros() - StatusTimer) > (STATUSDELAY * 1000)) { // ~50mS
|
||||
StatusTimer = micros();
|
||||
/* if (StatusSelect) StatusSelect = false;
|
||||
else StatusSelect = true;
|
||||
if (StatusSelect) CheckETXStatus(AzMotor);
|
||||
else CheckETXStatus(AltMotor);
|
||||
*/
|
||||
CheckETXStatus(AzMotor);
|
||||
CheckETXStatus(AltMotor);
|
||||
}
|
||||
|
||||
// Check any incoming characters from the EQMOD serial interface
|
||||
if (HBXCheckRx())
|
||||
EQGState(); // Check command state if data received
|
||||
if (EQGDone) { // EQG Rx complete, see what it is
|
||||
if (EQGErrorValue == 0) {
|
||||
EQGAction(); // and do it
|
||||
}
|
||||
else {
|
||||
EQGError(EQGErrorValue); // EQGAction() may set an error
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any characters that are ready to go to the WiFi interface
|
||||
while (EQGTxoPtr != EQGTxiPtr) {
|
||||
|
||||
// Send any characters that are ready to go to the WiFi interface
|
||||
digitalWrite(EQGLED, HIGH);
|
||||
HBXCheckTx();
|
||||
EQGTxoPtr &= EQGMASK;
|
||||
digitalWrite(EQGLED, LOW);
|
||||
}
|
||||
// TimerDelaymS(1);
|
||||
// yield();
|
||||
// HandleOTA();
|
||||
}
|
||||
|
||||
// End loop()
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG Protocol function definitions
|
||||
=================================
|
||||
*********************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CR 0x0d
|
||||
#define LF 0x0a
|
||||
|
||||
float SIDEREALSECS = 86164.098903691; // Some astronomical constants
|
||||
float SOLARSECS = 86400;
|
||||
float LUNARSECS = 89309;
|
||||
|
||||
#define SKYWATCHER_SIDEREAL_DAY 86164.09053083288
|
||||
#define SKYWATCHER_SIDEREAL_SPEED 15.04106864
|
||||
#define SKYWATCHER_STELLAR_DAY 86164.098903691
|
||||
#define SKYWATCHER_STELLAR_SPEED 15.041067179
|
||||
|
||||
#define EQG_CMNDSTART 0x01
|
||||
#define EQG_WAITFORCR 0x77
|
||||
#define EQG_INTERPRET 0x78
|
||||
|
||||
/*
|
||||
tmpMCVersion = Revu24str2long(response + 1);
|
||||
MCVersion = ((tmpMCVersion & 0xFF) << 16) | ((tmpMCVersion & 0xFF00)) | ((tmpMCVersion & 0xFF0000) >> 16);
|
||||
MountCode = MCVersion & 0xFF;
|
||||
*/
|
||||
|
||||
/*
|
||||
// Get Motor Controller Version
|
||||
// :em[0D]
|
||||
// ="llhhMM"[0D] (6 bytes - hex encoded)
|
||||
// Revu24str2long = MMhhll (3 bytes - binary encoded)
|
||||
// MCVersion = llhhMM (3 bytes - binary encoded)
|
||||
// MountCode = MM (1 byte - binary encoded)
|
||||
// =================================================================================
|
||||
// e 0 6 Get Motor Controller Version ="llhhMM"[0D] MM = mount code,
|
||||
// x00 = "EQ6Pro"
|
||||
// x01 = "HEQ5"
|
||||
// x02 = "EQ5"
|
||||
// x03 = "EQ3"
|
||||
// x04 = "EQ8"
|
||||
// x05 = "AZEQ6"
|
||||
// x06 = "AZEQ5"
|
||||
// x80 = "GT"
|
||||
// x81 = "MF"
|
||||
// x82 = "114GT"
|
||||
// x90 = "DOB"
|
||||
// hh.ll = board firmware version
|
||||
// hh=x00..x07 -> equatorial
|
||||
// =x08..xFF -> altaz
|
||||
*/
|
||||
// Get Axis Features
|
||||
// :qm[0D]
|
||||
// ="EFCDAB"[0D] (6 bytes - hex encoded)
|
||||
// AxisFeatures = EFCDAB (3 bytes - binary encoded)
|
||||
// A 8
|
||||
// 4
|
||||
// 2 in PPEC
|
||||
// 1 in PPECTraining
|
||||
|
||||
// B 8 is AZEQ
|
||||
// 4 has HomeIndexer
|
||||
// 2 has PPEC
|
||||
// 1 has Encoder
|
||||
|
||||
// C 8 has Wifi
|
||||
// 4 hasHalfCurrentTracking // ref :Wx06....
|
||||
// 2 has CommonSlewStart // Supports ":J3"
|
||||
// 1 has PolarLed
|
||||
/*
|
||||
// AxisFeatures = EFCDAB (3 bytes - binary encoded)
|
||||
// A
|
||||
AxisFeatures[Axis1].inPPECTraining = rafeatures & 0x00000010;
|
||||
AxisFeatures[Axis1].inPPEC = rafeatures & 0x00000020;
|
||||
// B
|
||||
AxisFeatures[Axis1].hasEncoder = rafeatures & 0x00000001;
|
||||
AxisFeatures[Axis1].hasPPEC = rafeatures & 0x00000002;
|
||||
AxisFeatures[Axis1].hasHomeIndexer = rafeatures & 0x00000004;
|
||||
AxisFeatures[Axis1].isAZEQ = rafeatures & 0x00000008;
|
||||
// C
|
||||
AxisFeatures[Axis1].hasPolarLed = rafeatures & 0x00001000;
|
||||
AxisFeatures[Axis1].hasCommonSlewStart = rafeatures & 0x00002000; // supports :J3
|
||||
AxisFeatures[Axis1].hasHalfCurrentTracking = rafeatures & 0x00004000;
|
||||
AxisFeatures[Axis1].hasWifi = rafeatures & 0x00008000;
|
||||
*/
|
||||
// Types
|
||||
enum SkywatcherCommand
|
||||
{
|
||||
Initialize = 'F',
|
||||
InquireMotorBoardVersion = 'e',
|
||||
InquireGridPerRevolution = 'a',
|
||||
InquireTimerInterruptFreq = 'b',
|
||||
InquireHighSpeedRatio = 'g',
|
||||
InquirePECPeriod = 's',
|
||||
InstantAxisStop = 'L',
|
||||
NotInstantAxisStop = 'K',
|
||||
SetAxisPositionCmd = 'E',
|
||||
GetAxisPosition = 'j',
|
||||
GetAxisStatus = 'f',
|
||||
SetSwitch = 'O',
|
||||
SetMotionMode = 'G',
|
||||
SetGotoTargetIncrement = 'H',
|
||||
SetBreakPointIncrement = 'M',
|
||||
SetGotoTarget = 'S',
|
||||
SetBreakStep = 'U',
|
||||
SetStepPeriod = 'I',
|
||||
StartMotion = 'J',
|
||||
GetStepPeriod = 'D',
|
||||
ActivateMotor = 'B', // See eq6direct implementation http://pierre.nerzic.free.fr/INDI/
|
||||
SetST4GuideRateCmd = 'P',
|
||||
GetHomePosition = 'd', // Get Home position encoder count (default at startup)
|
||||
SetFeatureCmd = 'W', // EQ8/AZEQ6/AZEQ5 only
|
||||
GetFeatureCmd = 'q', // EQ8/AZEQ6/AZEQ5 only
|
||||
InquireAuxEncoder = 'd', // EQ8/AZEQ6/AZEQ5 only
|
||||
NUMBER_OF_SkywatcherCommand
|
||||
};
|
||||
|
||||
enum SkywatcherAxis
|
||||
{
|
||||
Axis1 = 0, // RA/AZ
|
||||
Axis2 = 1, // DE/ALT
|
||||
NUMBER_OF_SKYWATCHERAXIS
|
||||
};
|
||||
char AxisCmd[2]{ '1', '2' };
|
||||
|
||||
enum SkywatcherDirection
|
||||
{
|
||||
BACKWARD = 0,
|
||||
FORWARD = 1
|
||||
};
|
||||
enum SkywatcherSlewMode
|
||||
{
|
||||
SLEW = 0,
|
||||
GOTO = 1
|
||||
};
|
||||
enum SkywatcherSpeedMode
|
||||
{
|
||||
LOWSPEED = 0,
|
||||
HIGHSPEED = 1
|
||||
};
|
||||
|
||||
typedef struct SkyWatcherFeatures
|
||||
{
|
||||
bool inPPECTraining = false;
|
||||
bool inPPEC = false;
|
||||
bool hasEncoder = false;
|
||||
bool hasPPEC = false;
|
||||
bool hasHomeIndexer = false;
|
||||
bool isAZEQ = false;
|
||||
bool hasPolarLed = false;
|
||||
bool hasCommonSlewStart = false; // supports :J3
|
||||
bool hasHalfCurrentTracking = false;
|
||||
bool hasWifi = false;
|
||||
} SkyWatcherFeatures;
|
||||
|
||||
enum SkywatcherGetFeatureCmd
|
||||
{
|
||||
GET_INDEXER_CMD = 0x00,
|
||||
GET_FEATURES_CMD = 0x01
|
||||
};
|
||||
|
||||
enum SkywatcherSetFeatureCmd
|
||||
{
|
||||
START_PPEC_TRAINING_CMD = 0x00,
|
||||
STOP_PPEC_TRAINING_CMD = 0x01,
|
||||
TURN_PPEC_ON_CMD = 0x02,
|
||||
TURN_PPEC_OFF_CMD = 0X03,
|
||||
ENCODER_ON_CMD = 0x04,
|
||||
ENCODER_OFF_CMD = 0x05,
|
||||
DISABLE_FULL_CURRENT_LOW_SPEED_CMD = 0x0006,
|
||||
ENABLE_FULL_CURRENT_LOW_SPEED_CMD = 0x0106,
|
||||
RESET_HOME_INDEXER_CMD = 0x08
|
||||
};
|
||||
|
||||
// Get Motor Controller Assets
|
||||
// :qm010000[0D]
|
||||
// =ABCDEF[0D]
|
||||
// ============
|
||||
// A 8 not defined
|
||||
// 4 not defined
|
||||
// 2 PPEC ON
|
||||
// 1 PPEC training in progress,
|
||||
// B 8 supports AZ/EQ
|
||||
// 4 has Home Sensors
|
||||
// 2 supports PPEC
|
||||
// 1 supports dual encoders
|
||||
// C 8 has WIFI
|
||||
// 4 supports half current tracking // ref :Wx06....
|
||||
// 2 axes slews must start independently // ie cant use :J3
|
||||
// 1 has polar LED
|
||||
// D 0000
|
||||
// E 0000
|
||||
// F 0000
|
||||
// EQ6 returns !0
|
||||
// ABCDEF
|
||||
// AZEQ5 =0B6000 at boot
|
||||
// AZEQ6 =0B3000
|
||||
// EQ8 =076000
|
||||
// ABCDEF
|
||||
|
||||
// Mount Assets
|
||||
// EFCDAB
|
||||
#define AEQ6 0x003000 // !:J3, PolarLED ; Real EQ6Pro
|
||||
#define AAEQ6 0x003008 // !:J3, PolarLED ; Pretend Az-EQ6
|
||||
#define AEQ5 0x003008 // !:J3, PolarLED ; AZ/EQ
|
||||
#define AEQ3 0x003000 // !:J3, PolarLED
|
||||
#define AAZEQ5 0x00B008 // WiFi, !:J3, PolarLED ; AZ/EQ
|
||||
#define AAZEQ6 0x00B008 // WiFi, !:J3, PolarLED ; AZ/EQ
|
||||
|
||||
// Motor firmware versions
|
||||
/*
|
||||
// Get Motor Controller Version
|
||||
// :e1[0D]
|
||||
// ="llhhMM"[0D] (6 bytes - hex encoded)
|
||||
// MountCode = MM (1 byte - binary encoded)
|
||||
// x00 = "EQ6Pro", x01 = "HEQ5", x02 = "EQ5", x03 = "EQ3", x04 = "EQ8", x05 = "AZEQ6", "AZEQ5"
|
||||
// x80 = "GT", x81 = "MF" , x82 = "114GT", x90 = "DOB"
|
||||
// hh.ll = board firmware version
|
||||
// hh = x00..x07 : equatorial
|
||||
// = x08..xFF : altaz
|
||||
*/
|
||||
#define VEQ6 0x000402 // Pretend EQ6 V 2.04 yyyy.mm.dd
|
||||
#define VAEQ6 0x050902 // Pretend Az-EQ6 V 2.09 yyyy.mm.dd
|
||||
#define VHEQ5 0x010204 // Pretend HEQ5 V 2.04 yyyy.mm.dd
|
||||
#define VEQ5 0x020207 // Pretend EQ5 V 2.07 yyyy.mm.dd
|
||||
#define VEQ3 0x030207 // Pretend EQ3 V 2.07 yyyy.mm.dd
|
||||
#define VEQ8 0x040211 // Pretend EQ8 V 2.11 2014.11.10
|
||||
#define VAZEQ6 0x050211 // Pretend AZEQ6 V 2.11 2014.11.10
|
||||
#define VAZEQ5 0x060301 // Pretend AZEQ5 V 3.01 2015.08.10
|
||||
|
||||
#define EQGVERSION VAEQ6 // For ETX, pretend to be an AltAz mount based on EQ6
|
||||
#define EQGASSETS AAEQ6 // For ETX, pretend to be an AltAz mount based on EQ6
|
||||
|
||||
|
||||
// :I := ( :b * (360*60*60) / :a ) / Speed ( where Speed is in arcsec/sec )
|
||||
// If :I is greater than about 10, then the slew will need to use :G = LoSpeed mode
|
||||
// If :I is less than 10, then the slew will need :G = HiRate, and :I := I * :g
|
||||
// a-AxxValue (Ticks/rev) := AxxVanes * 4 * AxxGbxRatio * ( Axx Transfer ) * AxxWormTeeth
|
||||
// b-AxxValue := 6460.09 * AxxRatio * a-AxxValue * 15.041069 / (360*60*60)
|
||||
|
||||
// Speed = g*(b*(360*60*60)/a)/I
|
||||
// ==============================
|
||||
// IVALUE = (axis[EQGMOTOR].bVALUE * (360*60*60)) / axis[EQGMOTOR].STEPSPER360)
|
||||
|
||||
#define EQG_gVALUE 0x000010
|
||||
#define EQGMAXIMUMSPEED 12
|
||||
|
||||
// EQG 'G' Command - SET move parameters
|
||||
#define DIRECTION 0x00000001 // Increasing(0) Decreasing(1)
|
||||
#define HEMISPHERE 0x00000002 // North(0) South(1)
|
||||
|
||||
// Get axis tracking/slewing "status"
|
||||
// EQG 'f' Command - GET Motor status bit definitions
|
||||
// =ABC[0D]
|
||||
// A xxx0 0 means GOTO, 1 means SLEW *** these are diff to :G usage
|
||||
// 0 means "actually doing" the goto. On stopping, it reverts to Slew Mode
|
||||
// xx0x 0 means +ve, 1 means -ve
|
||||
// x0xx 0 means LoRate, 1 means HiSpeed ***
|
||||
// B xxx0 0 means stopped, 1 means moving,
|
||||
// xx0x 0 means OK, 1 means blocked ( For DC motors only )
|
||||
// C xxx0 1 means axis is Initialised/Energised
|
||||
// xx0x 1 means level switch ON ( AltAz mounts and DEC only )
|
||||
|
||||
// MotorState bit definitions
|
||||
// A nibble1
|
||||
#define MOVESLEW 0x0001 // Step(0) Slew(1)
|
||||
#define MOVEDECR 0x0002 // Increasing(0) Decreasing(1)
|
||||
#define MOVEHIGH 0x0004 // Low(0) High(1)
|
||||
// B nibble2
|
||||
#define MOVEAXIS 0x0010 // Stopped(0) Moving(1)
|
||||
#define MOVEFACE 0x0020 // Front(0) Rear(1)
|
||||
// C nibble3
|
||||
#define MOVEACTIVE 0x0100 // Inactive(0) Active(1)
|
||||
|
||||
#define RATESLEWHI RATE2DEGREES
|
||||
#define RATESLEWLO RATESLEWHI >> 3
|
||||
#define RATEGOTOHI RATE1DEGREE
|
||||
#define RATEGOTOLO RATEGOTOHI >> 3
|
||||
|
||||
void EQGState(void);
|
||||
void EQGError(unsigned char);
|
||||
void EQGAction(void);
|
||||
|
||||
bool EQGRx(void);
|
||||
void EQGTx(unsigned char);
|
||||
void EQGTxHex(unsigned char);
|
||||
void EQGTxHex2(unsigned char);
|
||||
void EQGTxHex3(unsigned int);
|
||||
void EQGTxHex6(unsigned long);
|
||||
|
||||
// debug
|
||||
void putbyte(unsigned char);
|
||||
void putbyte(unsigned char);
|
||||
void puthexb(unsigned char);
|
||||
void puthexw(unsigned int);
|
||||
void puthexl(unsigned long);
|
||||
void putdecb(unsigned char);
|
||||
void putdecw(unsigned int);
|
||||
void putdecl(unsigned long);
|
|
@ -0,0 +1,988 @@
|
|||
/**@file*/
|
||||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
#include "Hardware.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "EQG2HBX.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXFileSystem.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
/*
|
||||
// EQG Protocol description
|
||||
// Courtesy Andrew Johansen - Yahoo Roboscope Group
|
||||
|
||||
// Transmit to EQG
|
||||
==================
|
||||
:CbDDDDDD[0D]
|
||||
C = command ( a..z, A..Z )
|
||||
b = controller ( 1 = Az, 2 = Alt, 3 = both )
|
||||
DDDDDD = data ( little endian ) uses 24bit little endian ( unless its a bitmapped command like :G )
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// Receive from EQG
|
||||
===================
|
||||
"=DDDDDD[0D]" // Data
|
||||
"!E[0D]" // Error
|
||||
= means success
|
||||
DDDDDD = data ( little endian ) uses 24bit little endian ( unless its a bitmapped command like :f, :q )
|
||||
! means error
|
||||
E is reason code
|
||||
Error E = 0 Invalid Command // the command doesn't apply to the model
|
||||
1 Invalid Paramcount // a valid command was passed with invalid parameter count
|
||||
2 Motor not Stopped // a valid command failed to run ( e.g. sending :G whilst motor is running )
|
||||
3 NonHex Param // the parameter contains a non uppercase Hex Char // Note! It doesn't mean an invalid parameter
|
||||
4 Not energised // motor is not energised
|
||||
5 Driver Asleep // controller is in sleep mode
|
||||
6
|
||||
7
|
||||
8 Invalid PPEC model
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
Values for Bytes sent
|
||||
:C DDDDDD bytes
|
||||
|
||||
Command, Bytes Sent, Nibbles Received, Description, // Example
|
||||
|
||||
sent rcvd
|
||||
a 0 6 Get microsteps per 360deg // =llhhLL[0D]
|
||||
b 0 6 Get timer interrupt freq // =llhhLL[0D]
|
||||
c 0 6 Get current ":U" value // =llhhLL[0D]
|
||||
d 0 6 Get Current Encoder count // =llhhLL[0D] default #x800000 = home ( this is synched somehow with :j Data )
|
||||
e 0 6 Get Motor Controller Version // =llhhMM[0D] MM = mount type,
|
||||
// x00 = "EQ6Pro"
|
||||
// x01 = "HEQ5"
|
||||
// x02 = "EQ5"
|
||||
// x03 = "EQ3"
|
||||
// x04 = "EQ8"
|
||||
// x05 = "AZEQ6"
|
||||
// x06 = "AZEQ5"
|
||||
// hh.ll = board version hh=x00..x07 = equatorial
|
||||
// =x08..xFF = altaz
|
||||
f 0 3 Get axis tracking/slewing "status" // =ABC[0D]
|
||||
// A xxx0 0 means GOTO, 1 means SLEW *** these are diff to :G usage
|
||||
// 0 means "actually doing" the goto. On stopping, it reverts to Slew Mode
|
||||
// xx0x 0 means +ve, 1 means -ve
|
||||
// x0xx 0 means LoSpeed, 1 means HiSpeed ***
|
||||
// B xxx0 0 means stopped, 1 means moving,
|
||||
// xx0x 0 means OK, 1 means blocked ( For DC motors only )
|
||||
// C xxx0 1 means axis is Initialised/Energised
|
||||
// xx0x 1 means level switch ON ( AltAz mounts and DEC only )
|
||||
g 0 2 Get HiSpeed multiplier // =llhhLL[0D] EQ6Pro, AZEQ5, EQ8 = 16 AZEQ6 = 32
|
||||
h 0 6 Get Current "goto" target // =llhhLL[0D] last value as set by :S or ( :j +/- :H )
|
||||
i 0 6 Get Current "slew" speed // =llhhLL[0D] must use with :f Hi/Lo and :g multiplier for correct value
|
||||
// Note! this value gets changed as a goto is done, ie a goto trumps any prev :I data
|
||||
// AZEQ5 changes as we do a goto, EQ6 only returns one value.
|
||||
j 0 6 Get Current Axis position. // =llhhLL[0D] Cardinal encoder count with #x800000 = 0 as a centre datum
|
||||
// DEC #x800000 = 0, pointing at West Horizon in Sth Hemi
|
||||
// DEC #xA26C80 = -90, pointing at Polar South in Sth Hemi
|
||||
// RA #x800000 = 0, CW shaft down
|
||||
k 1 6 :kx0[0D]=llhhLL[0D] gets running microstep count since last start/reset
|
||||
:kx1[0D]=llhhLL[0D] gets running microstep count since last start/reset then resets count
|
||||
// :k works on EQ6Pro, but not AZEQ5, AZEQ6, EQ8
|
||||
l ***
|
||||
m 0 6 Appears to be ramp up for a goto // =llhhLL[0D] ( ie :j +/- :M ) )
|
||||
// :J processing for EQ6Pro converts data to :h +/- :c if above low distance limit
|
||||
// to :h if below low distance limit
|
||||
n 0 2 Read EEProm Addr // =DD[0D] used with :C for peek ??? ####
|
||||
o ***
|
||||
p ***
|
||||
q 6 6 :qx000000[0D]=000000[0D] if axis is CW from home ( ie -ve ) just after home sensor trip has been reset
|
||||
=FFFFFF[0D] CCW from home ( ie +ve ) just after home sensor trip has been reset
|
||||
=llhhLL[0D] if sensor has tripped since reset ( use :W to clear data first )
|
||||
// AZEQ5 returns =000080 for Az and Alt
|
||||
:qx010000[0D]=ABCDEF[0D] ie the bitmapped nibbles for current status
|
||||
// A 8 not defined
|
||||
// 4 not defined
|
||||
// 2 PPEC ON
|
||||
// 1 PPEC training in progress,
|
||||
// B 8 supports AZ/EQ
|
||||
// 4 has Home Sensors
|
||||
// 2 supports PPEC
|
||||
// 1 supports dual encoders
|
||||
// C 8 has WIFI
|
||||
// 4 supports half current tracking // ref :Wx06....
|
||||
// 2 axes slews must start independently // ie cant use :J3
|
||||
// 1 has polar LED
|
||||
// D
|
||||
// E
|
||||
// F
|
||||
// EQ6 returns !0
|
||||
// AZEQ5 =0B6000 at boot
|
||||
// AZEQ6 =0B3000
|
||||
// EQ8 =076000
|
||||
r 0 2 Read Register Addr // =DD[0D] or =DDDD or =DDDDDD used with :A for peek ???
|
||||
// result appears to vary based on length of last valid data return ref test data done lower
|
||||
// AZEQ5 returns =[0D] ie no data if used directly after :A
|
||||
// must use :A then :g then :r ( ie the :g fake sets the return length to 2 )
|
||||
s 0 6 Get microsteps per worm rev // =llhhLL[0D] Used for wormwheel teeth calcs and PPEC
|
||||
t ***
|
||||
u ***
|
||||
v ***
|
||||
w ***
|
||||
x ***
|
||||
y ***
|
||||
z 0 0 Set Debug Flag // EQ6Pro returns !0[0D], AZEQ5/AZEQ6/EQ8 returns =[0D]
|
||||
|
||||
A 2 0 :AxHH[0D] Set Register Addr // used with :R and :r for Register poke/peek
|
||||
B ***
|
||||
C 4 0 :CxLLHH[0D] Set EEProm Addr // used with :N and :n for EEProm poke/peek
|
||||
D 0 6 :Dx[0D] Get 1x Track Rate // =llhhLL[0D] This is the :I rate used to give sidereal tracking
|
||||
E 6 0 :ExllhhLL[0D] Reset Axis datum to // used to synch encoder posn against a known HA/DEC )
|
||||
F 0 0 :Fx[0D] Initialise Target Axis ( energises motor )
|
||||
G 2 0 :GxAB[0D] Prepare slew parameters using bitmapped nybbles xAB
|
||||
// ( Note: ":f" is used to read the "current" actual status )
|
||||
// A = '0' high speed GOTO slewing, doesnt make "bitmapped" sense, but it is as coded by SkyWatcher????? ?????
|
||||
// '1' low speed slewing mode, all other bytes use bitmapping ( incl :f ), this doesnt
|
||||
// '2' low speed GOTO mode,
|
||||
// '3' high speed slewing mode
|
||||
// xxx0 0 means AutoGoto, 1 means manual slew or stopped
|
||||
// xx0x 0 means HiRate if Goto else LoRate if Slew
|
||||
// speed mode for AutoGoto is ignored for EQ6Pro
|
||||
// B = '0' +CW and Nth Hemi
|
||||
// '1' -CCW and Nth Hemi
|
||||
// '2' +CW and Sth Hemi
|
||||
// '3' -CCW and Sth Hemi
|
||||
// xxx0 0 means +ve, 1 = -ve "motor" direction, ie code takes care of whats N/S/E/W etc
|
||||
// +ve speed in RA is Axle moves CW when viewed from pole
|
||||
// +ve speed in DEC is Axle moves CCW when viewed from above
|
||||
// xx0x 0 means Nth Hemi else Sth Hemi ( ST4 guiding related ) ?????
|
||||
// Note! when using :S type gotos, the direction bit here "appears" to be ignored
|
||||
|
||||
H 6 0 :HxllhhLL[0D] Set goto target ( as a delta to current ) increment. Direction set by :G,
|
||||
I 6 0 :IxllhhLL[0D] Set Manual slewing rate ( read in conjunction with Hi/Lo rate as set by :G )
|
||||
J 0 0 :Jx[0D] Start moving
|
||||
K 0 0 :Kx[0D] Stop moving normal ( ramp if reqd )
|
||||
L 0 0 :Lx[0D] Stop moving Immediately
|
||||
M 6 0 :MxllhhLL[0D] Set break point increment // Doesnt appear to do anything ????? But possibly Ramp UP related
|
||||
// EQASCOM uses if H > 80000 then H - 80000 else H / 2
|
||||
// Indi uses HiSpeed if H > 3200 then 3200 else H/10 based on skywatcher code ( that also sets I )
|
||||
// LoSpeed if H > 200 then 200 else H/10
|
||||
// no values of :M appear to affect my EQ6 behaviour
|
||||
N 2 0 :NxHH[0D] Set EEProm Value to xHH // used with :C for poke?? NOT TESTED
|
||||
O 1 0 :OxA[0D] Toggle "Trigger/Snap Port" A = '1' = On, '0' = Off // EQ6 fires both at same time via Hbx, ie :O11 :O21
|
||||
// AZEQ5 can fire independently, EQ8 uses :O2x[0D] to fire its only port.
|
||||
P 1 0 :PxA[0D] set ST4 guiderate A = 0..4 = 1.0, 0.75, 0.50, 0.25, 0.125
|
||||
Q *** Set Bootloader Mode // Always uses :Qx55AA[0D] and has no response. 55AA looks like a flash unlock code ????
|
||||
R 2 0 :RxHH[0D] Set Register Value to xHH // used with :A for poke?? NOT TESTED
|
||||
S 6 0 :SxllhhLL[0D] Set absolute goto target // EQ8 also uses :M with this, but :M is absolute in EQ8 ?????
|
||||
// :S appears to ignore direction data set via :G
|
||||
T 6 0 :TxllhhLL[0D] Set LSB of speed // hhLL must be 0000. ie equivalent to :I = ll0000[0D] but works in HiSpeed mode ?????
|
||||
// Set Long Goto Step Period ( as per Synta )
|
||||
U 6 0 :UxllhhLL[0D] Set rampdown range // sets the microsteps from target where the rampdown process begins
|
||||
V 2 0 :VxHH[0D] Set Polar LED brightness // HH := x00 to xFF
|
||||
W 6 0 :Wx000000[0D] Start PPEC train
|
||||
:Wx010000[0D] Stop PPEC train
|
||||
:Wx020000[0D] Turn PPEC ON
|
||||
:Wx030000[0D] Turn PPEC OFF ( also sent when synch encoder used in EQ6 in 3.36. Not in 3.37 ???
|
||||
:Wx040000[0D] Encoder ON
|
||||
:Wx050000[0D] Encoder OFF
|
||||
:Wx060000[0D] Disable Full Current Low speed
|
||||
:Wx060100[0D] Enable Full Current Low speed
|
||||
:Wx07vvvv[0D] Set Stride for Slewing // need to test
|
||||
:Wx080000[0D] Reset Home Sensor datum
|
||||
X ***
|
||||
Y ***
|
||||
Z ***
|
||||
//=================================================================================================
|
||||
When setting "GOTO" data, it appears to require a correct sequence
|
||||
ie :G then :H then :M or
|
||||
:G then :S then :M for gotos.
|
||||
Mount must be stopped before sending :G here, or it chucks a fault.
|
||||
:M appears to have no function anymore????
|
||||
|
||||
:U appears to be standalone, and can be set at any time and is totally "sticky"
|
||||
Only appears to work so far with the EQ6Pro
|
||||
|
||||
When getting data we also need to get current status
|
||||
:j gets current offset
|
||||
:f is used first to check for current mode ie slew/goto, Hi/Lo, Fwd/Bwd so we know/can check signs for :h and :m
|
||||
:h gets current target ( should be ( :j + :H ) for Fwds, ( :j - :H ) for Bwds ) // ie same as :S
|
||||
:m gets ??? target ( should be ( :j + :M ) for Fwds, ( :j - :M ) for Bwds )
|
||||
:d gets the current quadrature encoder count ( if encoders are fitted ). Result is always true
|
||||
ie even if encoders are OFF, :d returns the true count.
|
||||
// *** WARNING *** :f always responds correctly to the latest :G
|
||||
// however, :h and :m do not. The :M and :H/:S must be sent AFTER :G
|
||||
// if you want to correctly reverse engineer settings from :h, :m
|
||||
|
||||
When setting "Slew" data, it also requires a set procedure
|
||||
Again :G sets direction and speed "range", and must be sent when stopped.
|
||||
:I is used to set the speed.
|
||||
The value used is basically the no of timer interrupts per microstep
|
||||
:I := ( :b * 86164 / :a ) / Speed ( where Speed is in arcsec/sec )
|
||||
Speed = g*(b*86164/9024000)/I
|
||||
If :I is greater than about 10, then the slew will need to use :G = LoSpeed mode
|
||||
If :I is less than 10, then the slew will need :G = HiRate, and :I := I * :g
|
||||
In LoSpeed mode, once moving, simply resending a new :I will cause the speed to change.
|
||||
In HiSpeed mode, you must issue a stop, resend :G, reset :I then restart.
|
||||
:b = :I * Speed/g * :a / 86164
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG Protocol related functions
|
||||
==============================
|
||||
*********************************************************/
|
||||
|
||||
// Process received EQG characters
|
||||
// ===============================
|
||||
void EQGState(void) {
|
||||
while ((EQGRxiPtr != EQGRxoPtr) && (EQGDone == 0)) {
|
||||
if (dbgFlag == 1) {
|
||||
if (EQGRxBuffer[EQGRxoPtr] == 'j')
|
||||
dbgFlag = 0;
|
||||
}
|
||||
if (EQGRxBuffer[EQGRxoPtr] == ':') {
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print(">>> ");
|
||||
dbgFlag++;
|
||||
}
|
||||
if (dbgFlag) {
|
||||
if ((EQGRxBuffer[EQGRxoPtr] != CR) && (EQGRxBuffer[EQGRxoPtr] != LF))
|
||||
dbgSerial.write(EQGRxBuffer[EQGRxoPtr]);
|
||||
else dbgSerial.write('.');
|
||||
// dbgSerial.write(EQGRxBuffer[EQGRxoPtr]);
|
||||
}
|
||||
|
||||
EQGRxChar = EQGRxBuffer[EQGRxoPtr++]; // Get a character
|
||||
if ((EQGRxState < EQG_WAITFORCR) && (EQGRxChar < ' ')) {
|
||||
EQGRxState = EQG_INTERPRET; // Terminate on non-alpha
|
||||
}
|
||||
|
||||
// Convert hex parameters to binary nibble
|
||||
// ---------------------------------------
|
||||
if ((EQGRxState > 0x03) && (EQGRxState < EQG_WAITFORCR)) {
|
||||
EQGRxChar = toupper(EQGRxChar);
|
||||
if ((EQGRxChar <= 'F') && (EQGRxChar >= '0')) {
|
||||
EQGRxChar -= '0';
|
||||
if (EQGRxChar > 9) EQGRxChar -= 0x07;
|
||||
}
|
||||
else EQGRxState = EQG_INTERPRET; // terminate on non-hex
|
||||
}
|
||||
|
||||
// Rx State machine
|
||||
// ----------------
|
||||
|
||||
switch (EQGRxState) {
|
||||
|
||||
case EQG_WAITFORCR: // Waiting for CR
|
||||
if (EQGRxChar == CR) {
|
||||
EQGRxState = EQG_CMNDSTART;
|
||||
EQGDone++;
|
||||
}
|
||||
break;
|
||||
|
||||
case EQG_CMNDSTART: // Waiting for ':'
|
||||
if (EQGRxChar == ':') {
|
||||
EQGRxCount = 1; // Count for # parameters
|
||||
EQGRxState++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02: // Waiting for command
|
||||
EQGCmnd = EQGRxChar;
|
||||
EQGRxCount++;
|
||||
EQGRxState++;
|
||||
break;
|
||||
|
||||
case 0x03: // Which motor?
|
||||
EQGRADEC = EQGRxChar;
|
||||
EQGMOTOR = EQGRADEC - '0';
|
||||
if ((EQGRADEC > '0') && (EQGRADEC < '3')) {
|
||||
EQGRxCount++;
|
||||
switch (EQGCmnd) { // Commands that have additional bytes
|
||||
case 'q': // Get mount assets
|
||||
case 'A': // Not used - Set Register Addr
|
||||
case 'B': // Unknown
|
||||
case 'C': // Not done - Set EEPROM Addr
|
||||
case 'E': // Set Current Position
|
||||
case 'G': // Set Move direction and speed multiplier
|
||||
case 'H': // Set GoTo Target Increment
|
||||
case 'I': // Set Speed
|
||||
case 'M': // Set BreakPoint Increment
|
||||
case 'N': // Not done - Set EEPROM
|
||||
case 'O': // Not done - Set trigger (0-off,1-on)
|
||||
case 'P': // Set AutoGuide Speed
|
||||
case 'R': // Not done - Set Register
|
||||
case 'S': // Not done - Set GoTo Target
|
||||
case 'T': // Unknown
|
||||
case 'U': // Not done - Set Break Step
|
||||
case 'V': // Set Polar LED brightness
|
||||
EQGRxState++; // Yes, so next state
|
||||
break;
|
||||
|
||||
default:
|
||||
EQGRxState = EQG_INTERPRET; // No, so command complete
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '3'; // Failure - Bad Parameters
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04: // First nibble
|
||||
EQGP1 = EQGRxChar; // EQGRxChar already converted to binary nibble
|
||||
EQGRxCount++; // Increase character count
|
||||
switch (EQGCmnd) { // Commands that send one nibble
|
||||
case 'B': // Not done - Unknown
|
||||
case 'O': // Set trigger (0-off,1-on)
|
||||
case 'P': // Set ST4 Guiderate
|
||||
EQGRxState = EQG_INTERPRET;
|
||||
break;
|
||||
default:
|
||||
EQGRxState++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05: // Second nibble - first byte (B1 = N1N2)
|
||||
EQGP2 = EQGRxChar; // EQGRxChar already converted to binary nibble
|
||||
EQGP1 = ((EQGP1 << 4) | EQGP2); // First byte
|
||||
EQGRxCount++;
|
||||
switch (EQGCmnd) { // Commands that send one byte
|
||||
case 'A': // Set register address
|
||||
case 'G': // Set direction, range
|
||||
case 'N': // Set EEPROM (:C) to xHH
|
||||
case 'R': // Set Register (:A) to xHH
|
||||
case 'V': // Set Polar LED brightness ro xHH
|
||||
EQGRxState = EQG_INTERPRET;
|
||||
break;
|
||||
default:
|
||||
EQGRxState++; // All the rest send 3 bytes
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: // Third nibble - N3N1N2
|
||||
EQGP2 = EQGRxChar; // EQGRxChar already converted to binary nibble
|
||||
EQGP1 |= (EQGP2 << 8);
|
||||
EQGRxCount++;
|
||||
EQGRxState++;
|
||||
break;
|
||||
|
||||
case 0x07: // Fourth nibble - N3N4N1N2
|
||||
EQGP1 &= 0xFF; // Clear all bar low byte
|
||||
EQGP1 |= (EQGP2 << 12); // Get N3 into correct position
|
||||
EQGP2 = EQGRxChar; // EQGRxChar already converted to binary nibble
|
||||
EQGP1 |= (EQGP2 << 8); // Get N4 into correct position
|
||||
EQGRxCount++;
|
||||
switch (EQGCmnd) { // Commands that send two bytes
|
||||
case 'C': // Set EEPROM address
|
||||
EQGRxState = EQG_INTERPRET;
|
||||
break;
|
||||
default:
|
||||
EQGRxState++; // All the rest send 3 bytes
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x08: // Fifth nibble - N5xxN3N4N1N2
|
||||
|
||||
EQGP2 = EQGRxChar;
|
||||
EQGP1 |= (EQGP2 << 20);
|
||||
EQGRxCount++;
|
||||
EQGRxState++; // Get next data
|
||||
break;
|
||||
|
||||
case 0x09: // Sixth nibble - N5N6N3N4N1N2
|
||||
|
||||
|
||||
EQGP2 = EQGRxChar;
|
||||
EQGP1 |= (EQGP2 << 16);
|
||||
EQGRxCount++;
|
||||
EQGRxState = EQG_INTERPRET; // All done
|
||||
break;
|
||||
|
||||
case EQG_INTERPRET:
|
||||
if ((EQGRxChar == 0x0d) && (EQGRxCount >= 3)) {
|
||||
EQGRxState = EQG_CMNDSTART; // Reset state machine
|
||||
switch (EQGCmnd) {
|
||||
// Commands that have no data
|
||||
case 'a': // Read steps per rotation
|
||||
case 'b': // Read tracking scale
|
||||
case 'c': // Read Motor Speed Change
|
||||
case 'd': // Read Current Encoder count
|
||||
case 'e': // Read firmware version
|
||||
case 'f': // Read motor status
|
||||
case 'g': // Read speed divisor
|
||||
case 'j': // Read position
|
||||
case 'm': // Read motor slowdown point
|
||||
case 'n': // Read EEPROM data
|
||||
case 'r': // Read register data
|
||||
case 's': // Read steps per arcsec
|
||||
case 'D': // Read track rate
|
||||
case 'F': // Energise motors
|
||||
case 'J': // GoTo position, track
|
||||
case 'K': // Stop movement
|
||||
EQGDone++;
|
||||
break;
|
||||
|
||||
// Commands that have three bytes
|
||||
// ==============================
|
||||
case 'q': // Read mount assets
|
||||
case 'E': // Set current position
|
||||
case 'H': // Set target position
|
||||
case 'I': // Set GoTo speed
|
||||
case 'M': // Set motor slowdown position ??
|
||||
case 'U': // Set motor slowdown speed ??
|
||||
if (EQGRxCount == (3 + 6)) {
|
||||
EQGDone++;
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '3'; // Failure - Bad Parameters
|
||||
}
|
||||
break;
|
||||
|
||||
// Commands that have two bytes
|
||||
case 'C': // Set EEPROM address
|
||||
if (EQGRxCount == (3 + 4)) {
|
||||
EQGDone++;
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '3'; // Failure - Bad Parameters
|
||||
}
|
||||
break;
|
||||
|
||||
// Commands that have one byte
|
||||
case 'A': // Set register address
|
||||
case 'G': // Set direction, range
|
||||
case 'N': // Set EEPROM (:C) to xHH
|
||||
case 'R': // Set Register (:A) to xHH
|
||||
case 'V': // Set LED Brightness to xHH
|
||||
if (EQGRxCount == (3 + 2)) {
|
||||
EQGDone++;
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '3'; // Failure - Bad Parameters
|
||||
}
|
||||
break;
|
||||
|
||||
// Commands that have one nibble
|
||||
case 'P': // Set autoguide speed
|
||||
case 'O': // Set Snap Port
|
||||
if (EQGRxCount == (3 + 1)) {
|
||||
EQGDone++;
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '3'; // Failure - Bad Parameters
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '0'; // Failure - Bad Command
|
||||
break;
|
||||
} // End - switch (EQGCmnd)
|
||||
}
|
||||
else {
|
||||
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
|
||||
else EQGDone++;
|
||||
EQGErrorValue = '0'; // Failure - Bad Command
|
||||
}
|
||||
break; // End - if (((EQGRxChar == 0x0d) || (EQGRxChar == 0x0a)) && (EQGRxCount >= 3))
|
||||
|
||||
default:
|
||||
EQGRxState = EQG_CMNDSTART;
|
||||
} // End - switch (EQGRxState)
|
||||
} // END - while ((EQGRxiPtr != EQGRxoPtr) && (EQGDone == 0))
|
||||
}
|
||||
|
||||
void EQGError(unsigned char errorbyte) {
|
||||
EQGTx('!') ; // Failure - Bad Parameters
|
||||
EQGTx(errorbyte);
|
||||
EQGTx(CR);
|
||||
EQGDone = 0; // Process errors
|
||||
EQGRxState = EQG_CMNDSTART;
|
||||
EQGRxCount = 0; // Count for # parameters
|
||||
EQGErrorValue = 0;
|
||||
}
|
||||
|
||||
// Received a valid command so execute it, if supported
|
||||
// ====================================================
|
||||
void EQGAction(void) {
|
||||
|
||||
EQGDone = 0; // Reset flag
|
||||
EQGRxState = EQG_CMNDSTART;
|
||||
EQGTx('='); // Answer (with parameters)
|
||||
|
||||
switch (EQGCmnd) {
|
||||
|
||||
case 'a': // Request total number of steps per revolution
|
||||
EQGTxHex6(axis[EQGMOTOR].aVALUE);
|
||||
break;
|
||||
|
||||
case 'b': // Request step interrupt frequency
|
||||
EQGTxHex6(axis[EQGMOTOR].bVALUE); // Let EQMOD calculate SIDEREAL, etc
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
EQGTxHex6(0x00D800); // Return same as EQ6 to keep the speed commands consistent
|
||||
break;
|
||||
|
||||
case 'd': // Request Mount center point
|
||||
// EQGTxHex6(EQG_CENTRE); // Return same as EQ6 to keep the speed commands consistent
|
||||
EQGTxHex6(axis[EQGMOTOR].Position);
|
||||
break;
|
||||
|
||||
case 'e': // Request version
|
||||
EQGTxHex6(EQGVERSION); //
|
||||
break;
|
||||
|
||||
case 'f': // Request motor status
|
||||
|
||||
// EQGMotorStatus bit definitions
|
||||
// A nibble1
|
||||
// MOVESLEW 0x0001 // Step(0) Slew(1)
|
||||
// MOVEDECR 0x0002 // Increasing(0) Decreasing(1)
|
||||
// MOVEHIGH 0x0004 // Low(0) High(1)
|
||||
// B nibble2
|
||||
// MOVEAXIS 0x0010 // Stopped(0) Moving(1)
|
||||
// MOVEFACE 0x0020 // Front(0) Rear(1)
|
||||
// C nibble3
|
||||
// MOVEACTIVE 0x0100 // Inactive(0) Active(1)
|
||||
|
||||
EQGTxHex3(axis[EQGMOTOR].EQGMotorStatus);
|
||||
|
||||
break;
|
||||
|
||||
case 'g': // Request speed multiplier
|
||||
EQGTxHex2(EQG_gVALUE); // Return same as EQ6 to keep the speed commands consistent
|
||||
break;
|
||||
|
||||
case 'j': // Request axis position
|
||||
EQGTxHex6(axis[EQGMOTOR].Position);
|
||||
break;
|
||||
|
||||
case 'm': // GET Point at which to change from fast to slow
|
||||
EQGTxHex6(axis[EQGMOTOR].SlowDown);
|
||||
break;
|
||||
|
||||
case 'q': // GET mount capabilities
|
||||
EQGTxHex6(EQGASSETS); // Say EQ and AZ
|
||||
break;
|
||||
|
||||
case 's': // PEC period
|
||||
EQGTxHex6(axis[EQGMOTOR].PEC);
|
||||
break;
|
||||
|
||||
case 'E': // Set current motor position
|
||||
if ((EQGP1 == 0x800000) || (EQGP1 == 0x85049c))
|
||||
break;
|
||||
else axis[EQGMOTOR].Position = EQGP1;
|
||||
break;
|
||||
|
||||
case 'F': // Initialize and activate motors
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVEACTIVE;
|
||||
axis[EQGMOTOR].ETXMotorStatus |= MOVEACTIVE;
|
||||
break;
|
||||
|
||||
case 'G': // EQG 'G' Command :GxAB[0D]
|
||||
|
||||
// See below for A
|
||||
// ===============
|
||||
// B nibble
|
||||
// --------
|
||||
// B = '0' +CW and Nthn Hemi
|
||||
// '1' -CCW and Nthn Hemi
|
||||
// '2' +CW and Sthn Hemi
|
||||
// '3' -CCW and Sthn Hemi
|
||||
// xxx0 0 means +ve, 1 = -ve "motor" direction, ie code takes care of whats N/S/E/W etc
|
||||
// +ve speed in RA is Axis moves CW when viewed from pole
|
||||
// +ve speed in DEC is Axis moves CCW when viewed from above (OTA horizontal, facing E->W ?)
|
||||
// xx0x 0 means Nthn Hemi else Sthn Hemi ( ST4 guiding related ) ?????
|
||||
// Note! when using :S type gotos, the direction bit here "appears" to be ignored
|
||||
// Also note that EQMOD does not appear to send the Hemisphere bit
|
||||
//
|
||||
// xxx0 CW(0) CCW(1) DIRECTION
|
||||
// xx0x North(0) South(1) HEMISPHERE
|
||||
|
||||
axis[EQGMOTOR].DirnSpeed = (int)EQGP1; // Save the command value
|
||||
switch (axis[EQGMOTOR].DirnSpeed & 0x03) {
|
||||
case 0x00:
|
||||
case 0x02:
|
||||
axis[EQGMOTOR].EQGMotorStatus &= ~MOVEDECR;
|
||||
dbgSerial.print(" +CW ");
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVEDECR;
|
||||
dbgSerial.print(" -CCW ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// When setting "Slew" data, it also requires a set procedure
|
||||
// G sets direction and speed "range", and must be sent when stopped.
|
||||
// A nibble
|
||||
// A = '0' high speed GOTO slewing, doesnt make "bitmapped" sense, but it is as coded by SkyWatcher
|
||||
// '1' low speed slewing mode, all other bytes use bitmapping ( incl :f ), this doesnt
|
||||
// '2' low speed GOTO mode,
|
||||
// '3' high speed slewing mode
|
||||
// xxx0 0 means AutoGoto, 1 means manual slew or stopped
|
||||
// xx0x 0 means HiRate if Goto else LoRate if Slew
|
||||
// speed mode for AutoGoto is ignored for EQ6Pro
|
||||
|
||||
// A
|
||||
switch ((EQGP1 >> 4) & 0x03) {
|
||||
case 00: // 0 HIGH SPEED GOTO
|
||||
axis[EQGMOTOR].EQGMotorStatus &= ~MOVESLEW; // GoTo target
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVEHIGH; // Enable high speed multiplier
|
||||
axis[EQGMOTOR].TargetSpeed = axis[EQGMOTOR].DEGREERATE1;
|
||||
dbgSerial.print("HIGH SPEED GOTO ");
|
||||
break;
|
||||
case 01: // 1 LOW SPEED SLEW
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVESLEW; // Just move the axis
|
||||
axis[EQGMOTOR].EQGMotorStatus &= ~MOVEHIGH; // Disable high speed multiplier
|
||||
axis[EQGMOTOR].TargetSpeed = (axis[EQGMOTOR].SIDEREALRATE);
|
||||
dbgSerial.print("LOW SPEED SLEW ");
|
||||
break;
|
||||
case 02: // 2 LOW SPEED GOTO
|
||||
axis[EQGMOTOR].EQGMotorStatus &= ~MOVESLEW; // GoTo target
|
||||
axis[EQGMOTOR].EQGMotorStatus &= ~MOVEHIGH; // Disable high speed multiplier
|
||||
axis[EQGMOTOR].TargetSpeed = (axis[EQGMOTOR].DEGREERATE1 << 3);
|
||||
dbgSerial.print("LOW SPEED GOTO ");
|
||||
break;
|
||||
case 03: // 3 HIGH SPEED SLEW
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVESLEW; // Just move the axis
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVEHIGH; // Enable high speed multiplier
|
||||
axis[EQGMOTOR].TargetSpeed = axis[EQGMOTOR].DEGREERATE1;
|
||||
dbgSerial.print("HIGH SPEED SLEW ");
|
||||
break;
|
||||
}
|
||||
dbgSerial.print(axis[EQGMOTOR].TargetSpeed);
|
||||
|
||||
axis[EQGMOTOR].ETXMotorStatus = axis[EQGMOTOR].EQGMotorStatus; // Copy the status for ETXProtocol
|
||||
break;
|
||||
|
||||
case 'H': // Set the goto target increment
|
||||
axis[EQGMOTOR].Increment = EQGP1;
|
||||
if (axis[EQGMOTOR].EQGMotorStatus & MOVEDECR)
|
||||
axis[EQGMOTOR].Target = axis[EQGMOTOR].Position - axis[EQGMOTOR].Increment; // subtract the relative target
|
||||
else
|
||||
axis[EQGMOTOR].Target = axis[EQGMOTOR].Position + axis[EQGMOTOR].Increment; // add the relative target
|
||||
axis[EQGMOTOR].MotorControl |= GoToHBX;
|
||||
break;
|
||||
|
||||
case 'I': // Set motor speed
|
||||
/*
|
||||
:I is used to set the speed.
|
||||
The value used is basically the number of timer interrupts per microstep
|
||||
------------------------------------------------------------------------
|
||||
I = (b * SiderealSecs / a) / Speed (where Speed is in arcsec/sec, SiderealSecs=86164.nn)
|
||||
Speed = g * (b * SiderealSecs / a) / I
|
||||
======================================
|
||||
If I is greater than about 10, then the slew will need to use :G = LoSpeed mode
|
||||
If I is less than 10, then the slew will need :G = HiRate, and :I = :I * :g
|
||||
In LoSpeed mode, once moving, simply resending a new :I will cause the speed to change.
|
||||
In HiSpeed mode, you must issue a stop, resend :G, reset :I then restart.
|
||||
b = I * Speed / g * a / SiderealSecs
|
||||
*/
|
||||
|
||||
axis[EQGMOTOR].EQGSpeed = EQGP1; // Set EQG speed value (I)
|
||||
axis[EQGMOTOR].TargetSpeed = EQGP1; // Set ETX target speed
|
||||
axis[EQGMOTOR].TargetSpeed = axis[EQGMOTOR].SIDEREALRATE * ((axis[EQGMOTOR].bVALUE*SIDEREALSECS)/axis[EQGMOTOR].aVALUE) / EQGP1;
|
||||
if (axis[EQGMOTOR].EQGMotorStatus & MOVEHIGH)
|
||||
axis[EQGMOTOR].TargetSpeed *= EQG_gVALUE;
|
||||
if (axis[EQGMOTOR].ETXMotorStatus & MOVEAXIS) // If already moving
|
||||
axis[EQGMOTOR].ETXMotorState = ETXStepMotor; // update speed
|
||||
break;
|
||||
|
||||
case 'J': // Tell motor to Go
|
||||
axis[EQGMOTOR].ETXMotorStatus |= MOVEAXIS; // Signal moving
|
||||
axis[EQGMOTOR].ETXMotorState = ETXCheckStartup; // General entry
|
||||
|
||||
break;
|
||||
|
||||
case 'K': // Tell motor to stop
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVESLEW; // Set slew as default
|
||||
axis[EQGMOTOR].ETXMotorStatus |= MOVESLEW; // Set slew as default
|
||||
axis[EQGMOTOR].TargetSpeed = 0;
|
||||
axis[EQGMOTOR].ETXMotorState = ETXCheckSpeed; // to enable motor slowdown
|
||||
break;
|
||||
|
||||
case 'L': // Tell motor to stop immediately
|
||||
axis[EQGMOTOR].EQGMotorStatus |= MOVESLEW; // Clear speed change
|
||||
axis[EQGMOTOR].ETXMotorStatus |= MOVESLEW; // Set slew as default
|
||||
axis[EQGMOTOR].TargetSpeed = 0;
|
||||
axis[EQGMOTOR].ETXMotorState = ETXStopMotor; // Immediate stop
|
||||
break;
|
||||
|
||||
case 'M': // Set the break point increment
|
||||
axis[EQGMOTOR].SlowDown = EQGP1;
|
||||
if ((axis[EQGMOTOR].EQGMotorStatus & MOVEDECR) == 0)
|
||||
axis[EQGMOTOR].SlowDown = axis[EQGMOTOR].Position + axis[EQGMOTOR].SlowDown; // add the relative target
|
||||
else
|
||||
axis[EQGMOTOR].SlowDown = axis[EQGMOTOR].Position - axis[EQGMOTOR].SlowDown; // subtract the relative target
|
||||
axis[EQGMOTOR].MotorControl |= GoToHBX; // Signal pending GoTo
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
axis[EQGMOTOR].HBXSnapPort = (char)EQGP1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
axis[EQGMOTOR].HBXGuide = (char)EQGP1;
|
||||
break;
|
||||
|
||||
case 'U': // Set the break point steps
|
||||
// JMA TODO axis[EQGMOTOR].SlowDown = EQGP1;
|
||||
break;
|
||||
|
||||
case 'V': // Set the LED brightness
|
||||
axis[EQGMOTOR].LEDValue = EQGP1;
|
||||
break;
|
||||
|
||||
default:
|
||||
EQGErrorValue = '0'; // Failure - Bad Command
|
||||
break;
|
||||
}
|
||||
EQGTx(CR);
|
||||
}
|
||||
|
||||
void EQGTxHex(unsigned char data) {
|
||||
if ((data & 0x0f) < 0x0a) EQGTx((data & 0x0f) + 0x30);
|
||||
else EQGTx((data & 0x0f) + 0x37);
|
||||
}
|
||||
|
||||
void EQGTxHex2(unsigned char data) {
|
||||
EQGTxHex(data >> 4);
|
||||
EQGTxHex(data);
|
||||
}
|
||||
|
||||
void EQGTxHex3(unsigned int data) {
|
||||
EQGTxHex((unsigned char)data);
|
||||
EQGTxHex((unsigned char)(data >> 4));
|
||||
EQGTxHex((unsigned char)(data >> 8));
|
||||
}
|
||||
|
||||
void EQGTxHex6(unsigned long data) {
|
||||
EQGTxHex2((unsigned char)data);
|
||||
EQGTxHex2((unsigned char)(data >> 8));
|
||||
EQGTxHex2((unsigned char)(data >> 16));
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
Debug routines
|
||||
***********************************************/
|
||||
void dbgRx(void) {
|
||||
while (dbgSerial.available() > 0) {
|
||||
dbgRxBuffer[dbgRxiPtr++] = dbgSerial.read();
|
||||
dbgRxiPtr &= dbgMASK;
|
||||
}
|
||||
}
|
||||
|
||||
void putbyte(unsigned char data) {
|
||||
dbgSerial.write(data);
|
||||
}
|
||||
|
||||
void puthexb(unsigned char data) {
|
||||
if (((data >> 4) & 0x0f) < 0x0a) putbyte(((data >> 4) & 0x0f) + 0x30);
|
||||
else putbyte(((data >> 4) & 0x0f) + 0x37);
|
||||
if ((data & 0x0f) < 0x0a) putbyte((data & 0x0f) + 0x30);
|
||||
else putbyte((data & 0x0f) + 0x37);
|
||||
}
|
||||
|
||||
void putdecb(unsigned char data) {
|
||||
dbgSerial.print(data);
|
||||
}
|
||||
|
||||
void puthexw(unsigned int data) {
|
||||
puthexb((data >> 8) & 0xFF);
|
||||
puthexb(data & 0xFF);
|
||||
}
|
||||
|
||||
void putdecw(unsigned int data) {
|
||||
dbgSerial.print(data);
|
||||
}
|
||||
|
||||
void puthex6(unsigned long data) {
|
||||
puthexb((data >> 16) & 0xFF);
|
||||
puthexw(data & 0xFFFF);
|
||||
}
|
||||
|
||||
void puthexl(unsigned long data) {
|
||||
puthexw((data >> 16) & 0xFFFF);
|
||||
puthexw(data & 0xFFFF);
|
||||
}
|
||||
|
||||
void putdecl(unsigned long data) {
|
||||
dbgSerial.print(data);
|
||||
}
|
||||
|
||||
void EQGSend(unsigned char data) {
|
||||
dbgSerial.write(data);
|
||||
}
|
||||
|
||||
void EQGSendHex(unsigned char data) {
|
||||
if ((data & 0x0f) < 0x0a) EQGSend((data & 0x0f) + 0x30);
|
||||
else EQGSend((data & 0x0f) + 0x37);
|
||||
}
|
||||
|
||||
void EQGSendHex2(unsigned char data) {
|
||||
EQGSendHex(data >> 4);
|
||||
EQGSendHex(data);
|
||||
}
|
||||
|
||||
void EQGSendHex6(unsigned long data) {
|
||||
EQGSendHex2((unsigned char)data);
|
||||
EQGSendHex2((unsigned char)(data >> 8));
|
||||
EQGSendHex2((unsigned char)(data >> 16));
|
||||
}
|
||||
|
||||
void debugEQG() {
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print("Az:<");
|
||||
dbgSerial.print(axis[AzMotor].EQGMotorStatus, HEX);
|
||||
dbgSerial.print("> Pos: ");
|
||||
dbgSerial.print(axis[AzMotor].Position, HEX);
|
||||
dbgSerial.print(" SD: ");
|
||||
dbgSerial.print(axis[AzMotor].SlowDown, HEX);
|
||||
dbgSerial.print(" Tgt: ");
|
||||
dbgSerial.print(axis[AzMotor].Target, HEX);
|
||||
dbgSerial.print(" Speed: ");
|
||||
dbgSerial.print(axis[AzMotor].ETXSpeed, HEX);
|
||||
|
||||
dbgSerial.print(", Alt:<");
|
||||
dbgSerial.print(axis[AltMotor].EQGMotorStatus, HEX);
|
||||
dbgSerial.print(">Pos: ");
|
||||
dbgSerial.print(axis[AltMotor].Position, HEX);
|
||||
dbgSerial.print(" SD: ");
|
||||
dbgSerial.print(axis[AltMotor].SlowDown, HEX);
|
||||
dbgSerial.print(" Tgt: ");
|
||||
dbgSerial.print(axis[AltMotor].Target, HEX);
|
||||
dbgSerial.print(" Speed: ");
|
||||
dbgSerial.print(axis[AltMotor].ETXSpeed, HEX);
|
||||
/*
|
||||
while (dbgRxoPtr != dbgRxiPtr) {
|
||||
dbgCommand[dbgIndex] = dbgRxBuffer[dbgRxoPtr]; // Copy character
|
||||
dbgSerial.write(dbgCommand[dbgIndex]);
|
||||
if ((dbgCommand[dbgIndex] != ':') && (dbgFlag == 0)) { // Wait for start of command string
|
||||
dbgSerial.write(dbgCommand[dbgIndex]); // Output to debug and skip
|
||||
}
|
||||
else {
|
||||
if (dbgCommand[dbgIndex] == CR) {
|
||||
dbgCommand[dbgIndex + 1] = 0;
|
||||
processdbgCommand();
|
||||
dbgFlag = 0;
|
||||
dbgIndex = 0;
|
||||
}
|
||||
else {
|
||||
dbgFlag |= 1;
|
||||
dbgIndex += 1;
|
||||
}
|
||||
}
|
||||
dbgRxoPtr += 1;
|
||||
dbgRxoPtr &= dbgMASK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Format - ":","Motor","Command","Paramters"
|
||||
// Motor 1, 2
|
||||
// Command t, w, g, v, x
|
||||
|
||||
void processdbgCommand(void) {
|
||||
unsigned char m, t;
|
||||
char argStr[256];
|
||||
|
||||
dbgSerial.println(""); dbgSerial.print("Scope: "); dbgSerial.println(telescope);
|
||||
dbgSerial.println(dbgCommand);
|
||||
|
||||
strcpy(argStr, &dbgCommand[3]);
|
||||
m = dbgCommand[2] - '1';
|
||||
if ((m == 0) || (m == 1)) {
|
||||
switch (dbgCommand[1]) {
|
||||
|
||||
case 't':
|
||||
t = dbgCommand[3] - '0';
|
||||
if (t > 9) t -= 7;
|
||||
if ((t >= 0) & (t < 16))
|
||||
telescope = t;
|
||||
dbgSerial.println(""); dbgSerial.print("Scope: "); dbgSerial.println(telescope);
|
||||
break;
|
||||
|
||||
case 'w': // Number of Worm teeth
|
||||
sscanf(argStr, "%ld", &v);
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print("WormTeeth: ");
|
||||
dbgSerial.print(argStr);
|
||||
dbgSerial.print(" ");
|
||||
dbgSerial.println(f);
|
||||
ratio[telescope][m].WormTeeth = v;
|
||||
break;
|
||||
|
||||
case 'g': // Gearbox Ratio (float)
|
||||
sscanf(argStr, "%f", &f); // Warning: you need the float libraries for this
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print("GearBox: "); // "-Wl,-u,vfscanf -lscanf_flt -lm" in platform.local.txt
|
||||
dbgSerial.print(argStr);
|
||||
dbgSerial.print(" ");
|
||||
dbgSerial.println(f);
|
||||
ratio[telescope][m].GbxRatio = f;
|
||||
break;
|
||||
|
||||
case 'v': // Number of optical vanes per revolution
|
||||
sscanf(argStr, "%ld", &v);
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print("Vanes: ");
|
||||
dbgSerial.print(argStr);
|
||||
dbgSerial.print(" ");
|
||||
dbgSerial.println(v);
|
||||
ratio[telescope][m].Vanes = v;
|
||||
break;
|
||||
|
||||
case 'x': // Gear transfer ratio
|
||||
sscanf(argStr, "%f", &f); // Warning: you need the float libraries for this
|
||||
dbgSerial.println("");
|
||||
dbgSerial.print("XferRatio: "); // "-Wl,-u,vfscanf -lscanf_flt -lm" in platform.local.txt
|
||||
dbgSerial.print(argStr);
|
||||
dbgSerial.print(" ");
|
||||
dbgSerial.println(f);
|
||||
ratio[telescope][m].XferRatio = f;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
PrintRatioValues(telescope);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
Handle EQG communications
|
||||
***********************************************/
|
||||
bool EQGRx(void) {
|
||||
if (EQGSerial.available() == 0)
|
||||
return false;
|
||||
digitalWrite(EQGLED, HIGH);
|
||||
while (EQGSerial.available() > 0) {
|
||||
EQGRxBuffer[EQGRxiPtr++] = EQGSerial.read();
|
||||
EQGRxiPtr &= EQGMASK;
|
||||
}
|
||||
digitalWrite(EQGLED, LOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Just put it in the output buffer
|
||||
// Main loop handles transmission
|
||||
void EQGTx(unsigned char data) {
|
||||
EQGTxBuffer[EQGTxiPtr++] = data;
|
||||
EQGTxiPtr &= EQGMASK;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG Protocol function definitions
|
||||
=================================
|
||||
*********************************************************/
|
||||
#pragma once
|
||||
|
||||
// Function Prototypes
|
||||
//
|
||||
void UpdateETX(void);
|
||||
void CheckETXStatus(unsigned char);
|
||||
void CheckETXState(unsigned char);
|
||||
|
||||
bool HBXGetStatus( unsigned char );
|
||||
bool ETXState( unsigned char );
|
||||
void AzInitialise( unsigned char );
|
||||
void AltInitialise( unsigned char );
|
||||
void WaitForMotors( void );
|
||||
void CalibrateLEDs( void);
|
||||
void HBXPrintStatus( unsigned char );
|
||||
bool HBXReset( void );
|
||||
|
||||
void PrintHbxValues( unsigned char );
|
||||
void PrintHbxValues( unsigned char );
|
||||
void dbgRx(void);
|
||||
|
||||
#define HBXAux 0x00 // The HBX interface port (Aux)
|
||||
#define MotorAz 0x01 // Pin7 on HBX interface
|
||||
#define MotorAlt 0x02 // Pin5 on HBX interface
|
||||
|
||||
uint8_t AuxHBX = HBXAux;
|
||||
uint8_t AzMotor = MotorAz;
|
||||
uint8_t AltMotor = MotorAlt;
|
||||
|
||||
// ETX Bit Definitions
|
||||
// Variable - axis[Motor].MotorControl
|
||||
// nibble 4
|
||||
#define StartHBX 0x8000 // Motor start bit
|
||||
#define StopHBX 0x4000 // Motor stop bit
|
||||
#define SlewHBX 0x2000 // Move in progress
|
||||
#define SpeedHBX 0x1000 // Speed change pending
|
||||
#define GoToHBX 0x0800 // GoTo in process
|
||||
|
||||
// ETX Known Commands
|
||||
#define SpeedChnge 0x00 // Update "8.16" speed
|
||||
#define SpeedStart 0x01 // Begin "8.16" speed
|
||||
#define SetOffset 0x02 // Output "16" correction offset
|
||||
#define SetLEDI 0x03 // Output "8" LED current
|
||||
#define CalibrateLED 0x04 // None
|
||||
#define Stop 0x05 // None
|
||||
#define SlewReverse 0x06 // None
|
||||
#define SlewForward 0x07 // None
|
||||
#define GetStatus 0x08 // Input "16.8.1" ticks.pwm.error
|
||||
#define GetLEDI 0x09 // Input "8" LED current
|
||||
#define GetMotorType 0x0B // Input "8" Motor type
|
||||
#define SleepHBX 0xE4 // None
|
||||
|
||||
#define OffsetMax 0x0020 // Maximum for a SetOffset command
|
||||
// ETX State Machine
|
||||
#define ETXIdle 0
|
||||
#define ETXCheckStartup 1
|
||||
#define ETXSlewMotor 2
|
||||
#define ETXStepMotor 3
|
||||
#define ETXCheckSlowDown 4
|
||||
#define ETXCheckSpeed 5
|
||||
#define ETXCheckPosition 6
|
||||
#define ETXCheckStop 7
|
||||
#define ETXStopMotor 8
|
||||
#define ETXMotorEnd 9
|
||||
// ETX axis State Machine
|
||||
#define NORMAL 0
|
||||
#define FLIP 1
|
||||
#define FLIPPED 2
|
||||
#define UNFLIP 3
|
||||
#define FLIPPING 4
|
||||
#define UNFLIPPING 5
|
||||
|
||||
const float ETX60PERIOD = 152.587891; // (1/6.5536mS)
|
||||
const unsigned long ETX_CENTRE = 0x00800000; // RA, DEC;
|
||||
|
||||
const float MeadeSidereal = 6460.0900; // Refer Andrew Johansen - Roboscope
|
||||
const float SiderealArcSecs = 15.041069; // Sidereal arcsecs/sec (ArcSec360/Sidereal secs)
|
||||
const float ArcSecs360 = 1296000; // Arcsecs / 360
|
||||
|
||||
|
||||
//#define ETXSlew0 .5 // .5 x sidereal (0.125 arc-min/sec or 0.0021°/sec)
|
||||
#define ETXSlew1 1 // 1 x sidereal (0.25 arc-min/sec or 0.0042°/sec)
|
||||
#define ETXSlew2 2 // 2 x sidereal (0.50 arc-min/sec or 0.0084°/sec)
|
||||
#define ETXSlew3 8 // 8 x sidereal ( 2 arc-min/sec or 0.0334°/sec)
|
||||
#define ETXSlew4 16 // 16 x sidereal ( 4 arc-min/sec or 0.0669°/sec)
|
||||
#define ETXSlew5 64 // 64 x sidereal ( 16 arc-min/sec or 0.2674°/sec)
|
||||
#define ETXSlew6 120 // 30 arc-min/sec or 0.5°/sec
|
||||
#define ETXSlew7 240 // 60 arc-min/sec or 1.0°/sec
|
||||
#define ETXSlew8 600 // 150 arc-min/sec or 2.5°/sec
|
||||
#define ETXSlew9 1080 // 270 arc-min/sec or 4.5°/sec
|
||||
|
||||
#define ETXSLOWPOSN 0x00000800 // Point at which to start slowdown
|
||||
|
||||
// bool HBXGetStatus(unsigned char);
|
||||
|
||||
/*
|
||||
bool HBXSetMotorState(unsigned char);
|
||||
bool HBXCheckTargetStatus(unsigned char);
|
||||
bool HBXUpdatePosn(void);
|
||||
bool HBXStartMotor(unsigned char);
|
||||
bool HBXStopMotor(unsigned char);
|
||||
void PositionPoll(unsigned char);
|
||||
*/
|
|
@ -0,0 +1,903 @@
|
|||
/**@file*/
|
||||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
#include "Hardware.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "EQG2HBX.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXFileSystem.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
|
||||
/********************************************************
|
||||
ETX Protocol related functions
|
||||
==============================
|
||||
*********************************************************/
|
||||
|
||||
bool ETXState(unsigned char Motor) {
|
||||
long distance;
|
||||
|
||||
switch(axis[Motor].ETXMotorState) {
|
||||
|
||||
case ETXIdle:
|
||||
break;
|
||||
|
||||
case ETXCheckStartup:
|
||||
if (axis[Motor].ETXMotorStatus & MOVEAXIS) { // Start moving
|
||||
//jma CheckAltFlip(Motor);
|
||||
|
||||
dbgSerial.println(""); dbgSerial.print("ETXCheckStartup - Motor: "); dbgSerial.print(axis_name[Motor]); dbgSerial.print(" MOVING");
|
||||
|
||||
if (axis[Motor].ETXMotorStatus & MOVESLEW) {
|
||||
axis[Motor].MotorControl |= SlewHBX;
|
||||
axis[Motor].ETXMotorState = ETXSlewMotor;
|
||||
if (axis[Motor].ETXMotorStatus & MOVEHIGH) { // Use high speed multiplier?
|
||||
dbgSerial.print(" HIGH SLEW"); // Ramp up to HIGH SPEED
|
||||
}
|
||||
else {
|
||||
axis[Motor].ETXMotorState = ETXStepMotor;
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command for next speed
|
||||
dbgSerial.print(" LOW SLEW");
|
||||
}
|
||||
}
|
||||
else { // GoTo or Low Speed Slew
|
||||
axis[Motor].MotorControl &= ~SlewHBX;
|
||||
axis[Motor].ETXMotorState = ETXCheckSpeed; // so just check speed
|
||||
dbgSerial.print(" GOTO");
|
||||
}
|
||||
|
||||
if (axis[Motor].MotorControl & GoToHBX) { // Check GoTo?
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // If it is decreasing
|
||||
distance = TwosComplement(distance);
|
||||
dbgSerial.printf(" Distance: %6lX, Tgt: %6lX, Pos: %6lX", distance, axis[Motor].Target, axis[Motor].Position);
|
||||
if (axis[Motor].MotorControl & SlewHBX) { // May need to slew for large changes
|
||||
axis[Motor].ETXMotorState = ETXSlewMotor; // Slew to M-point
|
||||
}
|
||||
else {
|
||||
axis[Motor].ETXMotorState = ETXCheckSpeed;
|
||||
axis[Motor].TargetSpeed = axis[Motor].DEGREERATE1; // Set initial speed for 'HIGH SPEED GOTO'
|
||||
if (distance < axis[Motor].OneDegree) // Scale target speed depending on distance to target
|
||||
axis[Motor].TargetSpeed = (axis[Motor].TargetSpeed >> 1); // 1/2
|
||||
if (distance < (axis[Motor].OneDegree >> 2))
|
||||
axis[Motor].TargetSpeed = (axis[Motor].TargetSpeed >> 1); // 1/4
|
||||
axis[Motor].ETXSpeed = 0; // Starting from 0
|
||||
dbgSerial.print(" GoTo-STEP");
|
||||
}
|
||||
if (distance < OffsetMax) { // Check for really small moves (< 16 steps)
|
||||
axis[Motor].ETXMotorState = ETXMotorEnd; // Use Adjust offset
|
||||
dbgSerial.print(" GoTo-OFFSET");
|
||||
}
|
||||
if (distance > (axis[Motor].OneDegree << 3)) { // Always slew for > 8 degrees
|
||||
axis[Motor].ETXMotorState = ETXSlewMotor;
|
||||
dbgSerial.print(" GoTo-SLEW");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ETXSlewMotor:
|
||||
//dbgSerial.println(""); dbgSerial.print("ETXSlewMotor Motor: "); dbgSerial.print(axis_name[Motor]); dbgSerial.print(" SLEW Cmd: ");
|
||||
/* Andrew Johansen Melbourne Australia
|
||||
All gotos are done in 2 phases
|
||||
In the first phase, it calcs distance to "target minus a set time"
|
||||
( ie it aims for a spot "behind" the target )
|
||||
It then starts slewing, at Max speed first if longer than a set distance.
|
||||
It checks distance intermittently and recalcs speed based on distance to go.
|
||||
When within a radius of about 40 arcsec it stops.
|
||||
It then recalcs for a position a few clock seconds ahead of target
|
||||
and does a second slew to finalise.
|
||||
It also sets a timer when starting the second slew.
|
||||
Once within about 10 arcsec of target, it stops until the timer trips
|
||||
then restarts tracking. ie no hunting around etc at the end,
|
||||
it just assumes it is correct.
|
||||
JMA
|
||||
In the ETX-arduino code, I do similar to what you have said previously.
|
||||
1. send a high speed command to get somewhere close (originally the breakpoint location)
|
||||
2. change to a low speed command to get closer (the maximum value of the offset command)
|
||||
3. read the current position from the ETX and issue an offset command to get to the target
|
||||
|
||||
0x06/0x07 Move at fastest rate (reverse/forward)
|
||||
0x01 Start moving, set speed and direction to the value specified in command
|
||||
0x00 While moving, adjust speed (but not direction) to the value specified in command
|
||||
0x02 Adjust position, while moving
|
||||
0x05 Stop moving
|
||||
|
||||
0x08 Return change in position
|
||||
|
||||
When, moving the speed set by subsequent 0x00 commands, appears to be ~0.8 of the previous speed.
|
||||
So the motor asymptotes down to a very low speed. And, at the end the 0x02 command adjusts the final position.
|
||||
|
||||
*/
|
||||
digitalWrite(ETXLED, HIGH); // Turn on the ETX telescope LED
|
||||
HBXSendCommand(Stop, Motor); // Stop the motor
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // -ve i.e. -CCW
|
||||
axis[Motor].Command = SlewReverse;
|
||||
else
|
||||
axis[Motor].Command = SlewForward;
|
||||
HBXSendCommand(axis[Motor].Command, Motor); // SLEW
|
||||
|
||||
axis[Motor].EQGMotorStatus |= MOVEAXIS; // Tell EQx
|
||||
axis[Motor].ETXSpeed = axis[Motor].DEGREERATE1; // Set ETXSpeed as approx (SLEW=DEGREERATE1) for later speed checks
|
||||
axis[Motor].ETXMotorState = ETXCheckPosition; // Preset position check
|
||||
|
||||
if (axis[Motor].MotorControl & GoToHBX) { // Check if slew was caused by a high speed long distance GoTo
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Check Distance to target
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // If it is decreasing
|
||||
distance = TwosComplement(distance);
|
||||
if (distance < axis[Motor].OneDegree) { // Change to GoTo if within one degree
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].ETXMotorState = ETXStepMotor;
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command for next speed
|
||||
axis[Motor].TargetSpeed = axis[Motor].DEGREERATE1; // Set initial speed
|
||||
axis[Motor].ETXSpeed = axis[Motor].DEGREERATE1;
|
||||
axis[Motor].SpeedState = 0;
|
||||
}
|
||||
}
|
||||
if (axis[Motor].MotorControl & SlewHBX) { // Slewing to M-point
|
||||
axis[Motor].ETXSpeed = axis[Motor].DEGREERATE1; // Indicate current speed (approx)
|
||||
axis[Motor].ETXMotorState = ETXCheckSlowDown; // Slew until SlowDown
|
||||
}
|
||||
|
||||
//*
|
||||
dbgSerial.println(""); dbgSerial.print("ETXSlewMotor Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Cmd: "); dbgSerial.print(axis[Motor].Command, HEX);
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
dbgSerial.print(", ETXSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TgtSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
dbgSerial.print(" SpeedState: "); dbgSerial.println(SpeedStateDesc[(axis[Motor].SpeedState)]);
|
||||
//*/
|
||||
break;
|
||||
|
||||
case ETXStepMotor:
|
||||
//*
|
||||
dbgSerial.println(""); dbgSerial.print("ETXStepMotor Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Cmd: "); dbgSerial.print(axis[Motor].Command, HEX);
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
dbgSerial.print(" Speed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
dbgSerial.print(" SpeedState: "); dbgSerial.println(SpeedStateDesc[(axis[Motor].SpeedState)]);
|
||||
//*/
|
||||
|
||||
digitalWrite(ETXLED, HIGH); // Turn on the LED
|
||||
if (axis[Motor].MotorControl & SpeedHBX) { // Stepping, High or Low speed
|
||||
axis[Motor].Command = SpeedStart; // Use SpeedStart to start motion
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Clear flag
|
||||
}
|
||||
else
|
||||
axis[Motor].Command = SpeedChnge; // Use SpeedChnge once started
|
||||
|
||||
// Set the speed, and direction
|
||||
// ----------------------------
|
||||
P1 = axis[Motor].TargetSpeed;
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // If negative, change P
|
||||
P1 = TwosComplement(P1); // to 2's complement
|
||||
axis[Motor].HBXP1 = (P1 >> 16) & 0xFF; // Initialize command bytes
|
||||
axis[Motor].HBXP2 = (P1 >> 8) & 0xFF;
|
||||
axis[Motor].HBXP3 = P1 & 0xFF;
|
||||
if (HBXSendCommand(axis[Motor].Command, Motor)) { // Send Command, check OK?
|
||||
HBXSend3Bytes(Motor); // Send the speed
|
||||
axis[Motor].EQGMotorStatus |= MOVEAXIS; // Tell EQx
|
||||
axis[Motor].ETXSpeed = axis[Motor].TargetSpeed;
|
||||
}
|
||||
else break;
|
||||
|
||||
axis[Motor].ETXMotorState = ETXCheckSpeed; // Preset Checkspeed, & if needed, make sure we are up to target speed
|
||||
if (axis[Motor].MotorControl & GoToHBX) { // If it is a GoTo and up to speed, check position
|
||||
if (axis[Motor].ETXSpeed == axis[Motor].TargetSpeed)
|
||||
axis[Motor].ETXMotorState = ETXCheckPosition;
|
||||
}
|
||||
else if (axis[Motor].ETXSpeed == 0) { // Stop issued
|
||||
axis[Motor].ETXMotorState = ETXStopMotor;
|
||||
}
|
||||
else if ((axis[Motor].MotorControl & SlewHBX) &&
|
||||
!(axis[Motor].MotorControl & GoToHBX)) { // SLEW without GoTo = speed change
|
||||
axis[Motor].ETXMotorState = ETXIdle;
|
||||
}
|
||||
else if (axis[Motor].ETXSpeed == axis[Motor].TargetSpeed) { // Else slewing at speed
|
||||
axis[Motor].ETXMotorState = ETXCheckPosition;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ETXCheckSlowDown:
|
||||
// Check if Slowdown reached
|
||||
// Calculate absolute distance to slowdown
|
||||
// ---------------------------------------
|
||||
|
||||
///*
|
||||
dbgSerial.println(""); dbgSerial.print("ETXCheckSlowDown Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Cmd: "); dbgSerial.print(axis[Motor].Command, HEX);
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print(" Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", SD: "); dbgSerial.print(axis[Motor].SlowDown, HEX);
|
||||
dbgSerial.print(", ETXSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TgtSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
//*/
|
||||
// distance = axis[Motor].SlowDown - axis[Motor].Position;
|
||||
distance = (axis[Motor].Target - 0x1000) - axis[Motor].Position; // Distance to target
|
||||
if (axis[Motor].Target < axis[Motor].Position) // If it is decreasing
|
||||
distance = TwosComplement(distance);
|
||||
|
||||
//dbgSerial.print(" distance: ");
|
||||
//dbgSerial.print(distance, HEX);
|
||||
|
||||
if (distance <= 0) {
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor
|
||||
// HBXSendCommand(Stop, Motor); // Stop the motor
|
||||
axis[Motor].TargetSpeed = (axis[Motor].SIDEREALRATE << 7); // target is 128xSidereal
|
||||
axis[Motor].ETXMotorState = ETXCheckSpeed;
|
||||
axis[Motor].MotorControl &= ~SlewHBX; // Clear slew bit (if it was set)
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command for first slow-down
|
||||
}
|
||||
break;
|
||||
|
||||
case ETXCheckSpeed:
|
||||
|
||||
/*
|
||||
ETXSlew1 1 // 1 x sidereal (0.25 arc-min/sec or 0.0042°/sec)
|
||||
ETXSlew2 2 // 2 x sidereal (0.50 arc-min/sec or 0.0084°/sec)
|
||||
ETXSlew3 8 // 8 x sidereal ( 2 arc-min/sec or 0.0334°/sec)
|
||||
ETXSlew4 16 // 16 x sidereal ( 4 arc-min/sec or 0.0669°/sec)
|
||||
ETXSlew5 64 // 64 x sidereal ( 16 arc-min/sec or 0.2674°/sec)
|
||||
ETXSlew6 120 // 30 arc-min/sec or 0.5°/sec
|
||||
ETXSlew7 240 // 60 arc-min/sec or 1.0°/sec
|
||||
ETXSlew8 600 // 150 arc-min/sec or 2.5°/sec
|
||||
ETXSlew9 1080 // 270 arc-min/sec or 4.5°/sec
|
||||
*/
|
||||
|
||||
///*
|
||||
dbgSerial.println(""); dbgSerial.print("ETXCheckSpeed Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print(" Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
dbgSerial.print(", ETXSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TgtSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
//*/
|
||||
// Speeding Up
|
||||
// ===========
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Preset set speed as next action
|
||||
// Ramp up to speed
|
||||
if ((axis[Motor].TargetSpeed != 0) && (axis[Motor].TargetSpeed > axis[Motor].ETXSpeed)) {
|
||||
if ((axis[Motor].TargetSpeed - axis[Motor].ETXSpeed) > (axis[Motor].SIDEREALRATE << 6)) { // 64x sidereal
|
||||
axis[Motor].ETXSpeed += ((axis[Motor].TargetSpeed - axis[Motor].ETXSpeed) >> 1); // Ramp up approx .5 difference
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command (changes speed, but not direction)
|
||||
}
|
||||
else {
|
||||
axis[Motor].ETXSpeed = axis[Motor].TargetSpeed;
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command (changes speed and direction)
|
||||
}
|
||||
}
|
||||
// Ramp down to speed
|
||||
else if ((axis[Motor].TargetSpeed != 0) && (axis[Motor].ETXSpeed > axis[Motor].TargetSpeed)) {
|
||||
axis[Motor].ETXSpeed -= ((axis[Motor].ETXSpeed - axis[Motor].TargetSpeed) >> 2); // Approx .75
|
||||
if ((axis[Motor].ETXSpeed - axis[Motor].TargetSpeed) <= (axis[Motor].SIDEREALRATE << 7)) {
|
||||
axis[Motor].ETXSpeed = axis[Motor].TargetSpeed; // Close enough at 128x sidereal, so set the speed
|
||||
// while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command (changes speed, but not direction)
|
||||
}
|
||||
}
|
||||
// Ramp down to stop
|
||||
else if ((axis[Motor].TargetSpeed == 0) && (axis[Motor].ETXSpeed != 0)) {
|
||||
if (axis[Motor].ETXMotorStatus & MOVESLEW) {
|
||||
axis[Motor].ETXMotorState = ETXStopMotor;
|
||||
}
|
||||
else if (axis[Motor].ETXSpeed >= (axis[Motor].SIDEREALRATE << 7)) { // Ramp down to 128 sidereal
|
||||
axis[Motor].ETXSpeed -= (axis[Motor].ETXSpeed >> 2); // Approximately .75
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command (changes speed and direction)
|
||||
}
|
||||
else
|
||||
axis[Motor].ETXMotorState = ETXStopMotor; // OK, Stop the motor
|
||||
}
|
||||
// Already stopped
|
||||
else if ((axis[Motor].TargetSpeed == 0) && (axis[Motor].ETXSpeed == 0)) {
|
||||
axis[Motor].ETXMotorStatus |= MOVESLEW; // ETX Set slewing mode
|
||||
axis[Motor].ETXMotorStatus &= ~MOVEHIGH; // and speed
|
||||
axis[Motor].ETXMotorStatus &= ~MOVEAXIS; // Clear the motor moving flag
|
||||
axis[Motor].MotorControl &= ~GoToHBX; // Clear the GoTo flag
|
||||
axis[Motor].MotorControl &= ~SlewHBX; // and the slew flag
|
||||
axis[Motor].EQGMotorStatus |= MOVESLEW; // EQG Set slewing mode
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEHIGH; // and speed
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEAXIS; // Clear the motor moving flag
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEDECR; // Clear the direction flag
|
||||
axis[Motor].ETXMotorState = ETXCheckStartup;
|
||||
}
|
||||
// Switch to position check, when we are at speed - check done in ETXStepMotor
|
||||
|
||||
//dbgSerial.print(" oSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
//dbgSerial.print(" oTargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
|
||||
break;
|
||||
|
||||
case ETXCheckPosition:
|
||||
// Check if Target acquired
|
||||
// ------------------------
|
||||
|
||||
// Calculate absolute distance to target
|
||||
// -------------------------------------
|
||||
|
||||
///*
|
||||
if ( ((Motor == MotorAlt) && ((pAltCount % 10) == 0)) ||
|
||||
((Motor == MotorAz) && ((pAzCount % 10) == 0)) ) {
|
||||
dbgSerial.println(""); dbgSerial.print("ETXCheckPosition Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
dbgSerial.print(", ETXSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TgtSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
}
|
||||
pAzCount++;
|
||||
pAltCount++;
|
||||
//*/
|
||||
if ( (axis[Motor].MotorControl & SlewHBX) &&
|
||||
!(axis[Motor].MotorControl & GoToHBX) ) // SLEW without GoTo = speed change
|
||||
break;
|
||||
|
||||
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // If it is decreasing
|
||||
distance = TwosComplement(distance);
|
||||
|
||||
if (distance == 0)
|
||||
axis[Motor].ETXMotorState = ETXMotorEnd;
|
||||
else if (distance > 0) {
|
||||
// Start to slow motor if getting near target
|
||||
// ------------------------------------------
|
||||
if (distance <= OffsetMax) {
|
||||
axis[Motor].ETXMotorState = ETXMotorEnd; // Stop motor, set offset
|
||||
axis[Motor].SpeedState = 0;
|
||||
}
|
||||
else if (axis[Motor].SpeedState == 3) {
|
||||
axis[Motor].TargetSpeed = (axis[Motor].SIDEREALRATE) << 2;
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
|
||||
axis[Motor].SpeedState += 1;
|
||||
}
|
||||
else if ((distance <= 0x200) && (axis[Motor].SpeedState == 2)) {
|
||||
axis[Motor].TargetSpeed = axis[Motor].ETXSpeed >> 2; // 1/16
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
|
||||
axis[Motor].SpeedState += 1;
|
||||
}
|
||||
else if ((distance <= 0x400) && (axis[Motor].SpeedState == 1)) {
|
||||
axis[Motor].TargetSpeed = axis[Motor].ETXSpeed >> 1; // 1/4
|
||||
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
|
||||
axis[Motor].SpeedState += 1;
|
||||
}
|
||||
else if ((distance <= 0x800) && (axis[Motor].SpeedState == 0)) {
|
||||
axis[Motor].TargetSpeed = axis[Motor].ETXSpeed >> 1; // 1/2
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
|
||||
axis[Motor].SpeedState += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((TwosComplement(distance)) > OffsetMax) { // Not sure how good offset is!
|
||||
// Motor has over-shot the target
|
||||
// ------------------------------
|
||||
if (axis[Motor].ETXMotorStatus & MOVEDECR) // ETX -> change direction
|
||||
axis[Motor].ETXMotorStatus &= ~MOVEDECR;
|
||||
else
|
||||
axis[Motor].ETXMotorStatus |= MOVEDECR;
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
|
||||
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command
|
||||
axis[Motor].TargetSpeed = (axis[Motor].SIDEREALRATE) << 2;
|
||||
axis[Motor].ETXMotorState = ETXStepMotor; // Change ETX speed
|
||||
}
|
||||
else{
|
||||
axis[Motor].ETXMotorState = ETXMotorEnd; // Stop motor, set offset
|
||||
axis[Motor].SpeedState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ETXStopMotor:
|
||||
|
||||
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor
|
||||
axis[Motor].ETXMotorStatus |= MOVESLEW; // ETX Set slewing mode
|
||||
axis[Motor].ETXMotorStatus &= ~MOVEHIGH; // and speed
|
||||
axis[Motor].ETXMotorStatus &= ~MOVEAXIS; // Clear the motor moving flag
|
||||
axis[Motor].MotorControl &= ~GoToHBX; // Clear the GoTo flag
|
||||
axis[Motor].MotorControl &= ~SlewHBX; // and the slew flag
|
||||
axis[Motor].EQGMotorStatus |= MOVESLEW; // EQG Set slewing mode
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEHIGH; // and speed
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEAXIS; // Clear the motor moving flag
|
||||
axis[Motor].EQGMotorStatus &= ~MOVEDECR; // Clear the direction flag
|
||||
axis[Motor].TargetSpeed = 0;
|
||||
axis[Motor].ETXSpeed = 0;
|
||||
axis[Motor].ETXMotorState = ETXCheckStartup;
|
||||
|
||||
//jma CheckAltFlipState();
|
||||
dbgSerial.println(""); dbgSerial.print("ETXStopMotor Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
dbgSerial.print(", ETXSpeed: "); dbgSerial.print(axis[Motor].ETXSpeed, HEX);
|
||||
dbgSerial.print(" TgtSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
|
||||
|
||||
break;
|
||||
|
||||
case ETXMotorEnd:
|
||||
///*
|
||||
dbgSerial.println(""); dbgSerial.print("ETXMotorEnd Motor: "); dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
|
||||
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
|
||||
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
|
||||
dbgSerial.print(" Chg: "); dbgSerial.print(axis[Motor].Position-axis[Motor].Target, HEX);
|
||||
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
|
||||
//*/
|
||||
digitalWrite(ETXLED, LOW); // Turn off the ETX LED
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
|
||||
if (axis[Motor].Target < axis[Motor].Position) // If it is decreasing
|
||||
distance = TwosComplement(distance);
|
||||
|
||||
if (distance == 0) {
|
||||
axis[Motor].ETXMotorState = ETXStopMotor; // Stop the motor
|
||||
}
|
||||
else {
|
||||
axis[Motor].HBXP1 = (distance >> 8) & 0xFF; // Initialize offset bytes
|
||||
axis[Motor].HBXP2 = distance & 0xFF;
|
||||
axis[Motor].Command = SetOffset;
|
||||
if (HBXSendCommand(axis[Motor].Command, Motor)) // Command OK?
|
||||
HBXSend2Bytes(Motor); // Send the offset
|
||||
|
||||
///*
|
||||
dbgSerial.print(" OFFSET");
|
||||
dbgSerial.print(" "); dbgSerial.print(axis[Motor].Command, HEX);
|
||||
dbgSerial.print(" "); dbgSerial.print(axis[Motor].HBXP1, HEX);
|
||||
dbgSerial.print(" "); dbgSerial.print(axis[Motor].HBXP2, HEX);
|
||||
dbgSerial.print(" "); dbgSerial.print(axis[Motor].HBXP3, HEX);
|
||||
//*/
|
||||
}
|
||||
axis[Motor].Position = axis[Motor].Target;
|
||||
axis[Motor].MotorControl &= ~GoToHBX; // Clear the flag
|
||||
axis[Motor].ETXMotorState = ETXStopMotor;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Motor functions
|
||||
|
||||
bool HBXGetStatus(unsigned char Motor) {
|
||||
if (!HBXSendCommand(GetStatus, Motor)) {
|
||||
dbgSerial.println(""); dbgSerial.print("HBXGetStatus Motor: "); dbgSerial.print(axis_name[Motor]); dbgSerial.println(" Cmd Fail");
|
||||
return(false);
|
||||
}
|
||||
HBXGet3Bytes(Motor);
|
||||
P1 = (axis[Motor].HBXP1 << 8); // Update calculated position
|
||||
P1 |= axis[Motor].HBXP2; // Convert to 16bits
|
||||
if (axis[Motor].HBXP1 & 0x80)
|
||||
P1 |= 0xffff0000; // Sign extend HBXP1 for 2s complement
|
||||
axis[Motor].Position += P1;
|
||||
|
||||
// Wrap the position if above (+12H or +90deg)
|
||||
if (axis[Motor].Position >= (ETX_CENTRE + (axis[Motor].aVALUE >> 1)))
|
||||
axis[Motor].Position -= axis[Motor].aVALUE;
|
||||
// Wrap the position if below (-12H or -90deg)
|
||||
if (axis[Motor].Position <= (ETX_CENTRE - (axis[Motor].aVALUE >> 1)))
|
||||
axis[Motor].Position += axis[Motor].aVALUE;
|
||||
|
||||
if (StatusCount++ > 51) {
|
||||
StatusCount = 0;
|
||||
dbgSerial.print(axis_name[MotorAlt]); dbgSerial.print(": "); dbgSerial.print(axis[MotorAlt].Position, HEX); dbgSerial.print(", ");
|
||||
dbgSerial.print(axis_name[MotorAz]); dbgSerial.print(": "); dbgSerial.println(axis[MotorAz].Position, HEX);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool HBXGet2Status(void) {
|
||||
int i;
|
||||
do {
|
||||
i = 0;
|
||||
if (HBXGetStatus(AzMotor)) i += 1;
|
||||
TimerDelayuS(HBXBitTime << 2);
|
||||
|
||||
if (HBXGetStatus(AltMotor)) i += 1;
|
||||
TimerDelayuS(HBXBitTime << 2);
|
||||
|
||||
} while (i < 2);
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Calibrate motor LED
|
||||
// ===================
|
||||
void CalibrateLEDs(void) {
|
||||
|
||||
|
||||
while (!(HBXSendCommand(Stop, AzMotor))); // Stop both motors
|
||||
TimerDelaymS(100);
|
||||
while (!(HBXSendCommand(Stop, AltMotor)));
|
||||
TimerDelaymS(100);
|
||||
|
||||
while (!(HBXGetStatus(AzMotor)))
|
||||
TimerDelaymS(100);
|
||||
while (!(HBXGetStatus(AltMotor)))
|
||||
TimerDelaymS(100);
|
||||
|
||||
HBXSendCommand(SleepHBX, AzMotor); // Issue Sleep
|
||||
TimerDelaymS(100);
|
||||
HBXSendCommand(CalibrateLED, AzMotor); // Issue Calibrate LED
|
||||
TimerDelaymS(4000);
|
||||
|
||||
HBXSendCommand(SleepHBX, AltMotor);
|
||||
TimerDelaymS(100);
|
||||
HBXSendCommand(CalibrateLED, AltMotor);
|
||||
TimerDelaymS(4000);
|
||||
|
||||
HBXSendCommand(GetLEDI, AzMotor); HBXGetByte(AzMotor);
|
||||
HBXSendCommand(GetLEDI, AltMotor); HBXGetByte(AltMotor);
|
||||
|
||||
while (!(HBXGetStatus(AzMotor)))
|
||||
TimerDelaymS(100);
|
||||
while (!(HBXGetStatus(AltMotor)))
|
||||
TimerDelaymS(100);
|
||||
|
||||
// Read the calibration
|
||||
dbgSerial.println(""); dbgSerial.print("Read LEDs - AzMotor: ");
|
||||
if (HBXSendCommand(GetLEDI, AzMotor))
|
||||
axis[AzMotor].HBXLEDI = HBXGetByte(AzMotor);
|
||||
dbgSerial.print(axis[AzMotor].HBXLEDI);
|
||||
dbgSerial.print(", AltMotor: ");
|
||||
if (HBXSendCommand(GetLEDI, AltMotor))
|
||||
axis[AltMotor].HBXLEDI = HBXGetByte(AltMotor);
|
||||
dbgSerial.print(axis[AltMotor].HBXLEDI);
|
||||
|
||||
// Save it to preferences
|
||||
// Prefences.begin must be set by the caller
|
||||
preferences.putUChar("AzLEDI", axis[AzMotor].HBXLEDI);
|
||||
preferences.putUChar("AltLEDI", axis[AltMotor].HBXLEDI);
|
||||
}
|
||||
|
||||
void WaitForMotors(void) {
|
||||
// GetLED commands always return a vaild value - motors not online until this happens
|
||||
// "Valid" values are not 0 and not 0xFF for Az, Alt. (exception here is if LEDRA || LEDAlt == 0xff)
|
||||
//
|
||||
bool PAz = false;
|
||||
bool PAlt = false;
|
||||
do {
|
||||
if (!PAz) {
|
||||
if (HBXSendCommand(GetLEDI, AzMotor))
|
||||
axis[AzMotor].HBXLEDI = HBXGetByte(AzMotor);
|
||||
dbgSerial.print("Az HBXLEDI: "); dbgSerial.println(axis[AzMotor].HBXLEDI);
|
||||
TimerDelaymS(CMNDTIME);
|
||||
if ((axis[AzMotor].HBXLEDI != 0) && (axis[AzMotor].HBXLEDI != 0xFF))
|
||||
PAz = true;
|
||||
}
|
||||
if (!PAlt) {
|
||||
if (HBXSendCommand(GetLEDI, AltMotor))
|
||||
axis[AltMotor].HBXLEDI = HBXGetByte(AltMotor);
|
||||
TimerDelaymS(CMNDTIME);
|
||||
dbgSerial.print("Alt HBXLEDI: "); dbgSerial.println(axis[AltMotor].HBXLEDI);
|
||||
if ((axis[AltMotor].HBXLEDI != 0) && (axis[AltMotor].HBXLEDI != 0xFF))
|
||||
PAlt = true;
|
||||
}
|
||||
// Attempt to reset Motor Controller
|
||||
if (!PAz) {
|
||||
HBXMotorReset(AzMotor);
|
||||
}
|
||||
if (!PAlt) {
|
||||
HBXMotorReset(AltMotor);
|
||||
}
|
||||
} while ((!PAz) || (!PAlt));
|
||||
}
|
||||
|
||||
void AzInitialise(unsigned char scope) {
|
||||
// Telescope specific
|
||||
// telescope steps
|
||||
axis[AzMotor].Vanes = ratio[scope][AzMotor-1].Vanes;
|
||||
axis[AzMotor].GbxRatio = ratio[scope][AzMotor-1].GbxRatio;
|
||||
axis[AzMotor].XferRatio = ratio[scope][AzMotor-1].XferRatio;
|
||||
axis[AzMotor].WormTeeth = ratio[scope][AzMotor-1].WormTeeth;
|
||||
// EQMOD
|
||||
axis[AzMotor].aVALUE = axis[AzMotor].Vanes * (float)4 * axis[AzMotor].GbxRatio * axis[AzMotor].XferRatio * axis[AzMotor].WormTeeth;
|
||||
axis[AzMotor].MeadeRatio = (float)axis[AzMotor].aVALUE / ArcSecs360; // Count for one arcsec
|
||||
axis[AzMotor].bVALUE = (MeadeSidereal * axis[AzMotor].MeadeRatio) * ((float)axis[AzMotor].aVALUE / SIDEREALSECS) * SiderealArcSecs;
|
||||
axis[AzMotor].BASERATE = axis[AzMotor].bVALUE / axis[AzMotor].MeadeRatio;
|
||||
axis[AzMotor].SIDEREALRATE = MeadeSidereal * axis[AzMotor].MeadeRatio;
|
||||
axis[AzMotor].SOLARRATE = axis[AzMotor].SIDEREALRATE * SOLARSECS / SIDEREALSECS;
|
||||
axis[AzMotor].LUNARRATE = axis[AzMotor].SIDEREALRATE * LUNARSECS / SIDEREALSECS;
|
||||
axis[AzMotor].DEGREERATE1 = axis[AzMotor].SIDEREALRATE * ETXSlew7;
|
||||
axis[AzMotor].PEC = axis[AzMotor].aVALUE / axis[AzMotor].WormTeeth;
|
||||
|
||||
// ETX
|
||||
axis[AzMotor].HBXP1 = 0x00;
|
||||
axis[AzMotor].HBXP2 = 0x00;
|
||||
axis[AzMotor].HBXP3 = 0x00;
|
||||
axis[AzMotor].HBXP4 = 0x00;
|
||||
axis[AzMotor].ETXSpeed = 0x00;
|
||||
axis[AzMotor].SpeedState = 0x00;
|
||||
axis[AzMotor].TargetSpeed = axis[AzMotor].SIDEREALRATE;
|
||||
axis[AzMotor].Position = ETX_CENTRE; // ETX RA initially at 0 hours
|
||||
axis[AzMotor].OneDegree = axis[AzMotor].aVALUE / (float)360; // Distance for one degree
|
||||
axis[AzMotor].Target = axis[AzMotor].Position;
|
||||
axis[AzMotor].DirnSpeed = 0x000;
|
||||
axis[AzMotor].ETXMotorStatus = MOVESLEW;
|
||||
axis[AzMotor].EQGMotorStatus = MOVESLEW;
|
||||
axis[AzMotor].ETXMotorState = ETXCheckStartup;
|
||||
}
|
||||
|
||||
void AltInitialise(unsigned char scope) {
|
||||
// Telescope specific
|
||||
// telescope steps
|
||||
axis[AltMotor].Vanes = ratio[scope][AltMotor-1].Vanes;
|
||||
axis[AltMotor].GbxRatio = ratio[scope][AltMotor-1].GbxRatio;
|
||||
axis[AltMotor].XferRatio = ratio[scope][AltMotor-1].XferRatio;
|
||||
axis[AltMotor].WormTeeth = ratio[scope][AltMotor-1].WormTeeth;
|
||||
// EQMOD
|
||||
axis[AltMotor].aVALUE = axis[AltMotor].Vanes * (float)4 * axis[AltMotor].GbxRatio * axis[AltMotor].XferRatio * axis[AltMotor].WormTeeth;
|
||||
axis[AltMotor].MeadeRatio = axis[AltMotor].aVALUE / ArcSecs360; // Count for one arcsec
|
||||
axis[AltMotor].bVALUE = (MeadeSidereal * axis[AltMotor].MeadeRatio) * (axis[AltMotor].aVALUE / SIDEREALSECS) * SiderealArcSecs;
|
||||
axis[AltMotor].BASERATE = axis[AltMotor].bVALUE / axis[AltMotor].MeadeRatio;
|
||||
axis[AltMotor].SIDEREALRATE = MeadeSidereal * axis[AltMotor].MeadeRatio;
|
||||
axis[AltMotor].SOLARRATE = axis[AltMotor].SIDEREALRATE * SOLARSECS / SIDEREALSECS;
|
||||
axis[AltMotor].LUNARRATE = axis[AltMotor].SIDEREALRATE * LUNARSECS / SIDEREALSECS;
|
||||
axis[AltMotor].DEGREERATE1 = axis[AltMotor].SIDEREALRATE * ETXSlew7;
|
||||
axis[AltMotor].PEC = axis[AltMotor].aVALUE / axis[AltMotor].WormTeeth;
|
||||
axis[AltMotor].EQGMotorStatus = MOVESLEW;
|
||||
// ETX
|
||||
axis[AltMotor].HBXP1 = 0x00;
|
||||
axis[AltMotor].HBXP2 = 0x00;
|
||||
axis[AltMotor].HBXP3 = 0x00;
|
||||
axis[AltMotor].HBXP4 = 0x00;
|
||||
axis[AltMotor].ETXSpeed = 0x00;
|
||||
axis[AltMotor].SpeedState = 0x00;
|
||||
axis[AltMotor].TargetSpeed = axis[AzMotor].SIDEREALRATE;
|
||||
axis[AltMotor].Position = ETX_CENTRE; // + (axis[AltMotor].aVALUE >> 2); // Initially at +90 degrees
|
||||
axis[AltMotor].OneDegree = axis[AltMotor].aVALUE / (float)360; // Distance for one degree
|
||||
axis[AltMotor].Target = axis[AltMotor].Position;
|
||||
axis[AltMotor].DirnSpeed = 0x000;
|
||||
axis[AltMotor].ETXMotorStatus = MOVESLEW;
|
||||
|
||||
axis[AltMotor].ETXMotorState = ETXCheckStartup;
|
||||
}
|
||||
|
||||
/*
|
||||
// Check if ETX mount will hit fork physical limits
|
||||
// When used as GEM, ETX mounts cannot go past vertical
|
||||
// This means E in Sthn, W in Nthn, for East side pointing West
|
||||
// So rotate 180 degrees in Az and flip the Alt destination
|
||||
*/
|
||||
void CheckAltFlip(unsigned char Motor) {
|
||||
long distance;
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
|
||||
if ((telescope < 3) && (Motor == AltMotor)) { // ETXn0 series
|
||||
long p;
|
||||
if (distance > 0) {
|
||||
// GoTo
|
||||
if (axis[AltMotor].Target >= (ETX_CENTRE + (axis[AltMotor].aVALUE >> 2))) { // E[Sthn] (or W[Nthn])
|
||||
dbgSerial.println(""); dbgSerial.print("Flip: target "); dbgSerial.print(axis[AltMotor].Target); // Set Target
|
||||
p = axis[AltMotor].Target - (ETX_CENTRE + (axis[AltMotor].aVALUE >> 2)); // Offset from EQG midpoint
|
||||
axis[AltMotor].Target -= (p << 1); // Swap to other side
|
||||
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
|
||||
dbgSerial.print(", new "); dbgSerial.print(axis[AltMotor].Target);
|
||||
// Flip direction
|
||||
if (axis[AltMotor].ETXMotorStatus & MOVEDECR) axis[AltMotor].ETXMotorStatus &= ~MOVEDECR;
|
||||
else axis[AltMotor].ETXMotorStatus |= MOVEDECR;
|
||||
// Set SlowDown
|
||||
p = axis[AltMotor].SlowDown - (ETX_CENTRE + (axis[AltMotor].aVALUE >> 2));
|
||||
axis[AltMotor].SlowDown -= (p << 1);
|
||||
dbgSerial.print(", Slowdown "); dbgSerial.print(p);
|
||||
if (axis[AltMotor].Flip == NORMAL) {
|
||||
axis[AltMotor].Flip = FLIP;
|
||||
dbgSerial.print(", Type "); dbgSerial.print("ALREADY FLIPPED");
|
||||
}
|
||||
else {
|
||||
dbgSerial.print(", Type "); dbgSerial.print("NORMAL");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (axis[AltMotor].Flip == FLIPPED) {
|
||||
axis[AltMotor].Flip = UNFLIP;
|
||||
dbgSerial.print(", Action "); dbgSerial.print("UNFLIP");
|
||||
}
|
||||
else {
|
||||
dbgSerial.print(", Action "); dbgSerial.print("NOTHING");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// SLEW
|
||||
if (axis[AltMotor].ETXMotorStatus & MOVEDECR) {
|
||||
axis[AltMotor].ETXMotorStatus &= ~MOVEDECR;
|
||||
if (axis[AltMotor].Flip == NORMAL) {
|
||||
axis[AltMotor].Flip = FLIP;
|
||||
dbgSerial.print(", Action "); dbgSerial.print("FLIP");
|
||||
}
|
||||
else {
|
||||
dbgSerial.print(", Action "); dbgSerial.print("NOTHING");
|
||||
}
|
||||
}
|
||||
if (axis[AltMotor].Flip == FLIPPED) {
|
||||
axis[AltMotor].Flip = UNFLIP;
|
||||
dbgSerial.print(", Action "); dbgSerial.print("FLIP");
|
||||
}
|
||||
else {
|
||||
dbgSerial.print(", Action "); dbgSerial.print("NOTHING");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckAltFlipState(void) {
|
||||
if ((axis[AltMotor].Flip == FLIPPING) || (axis[AltMotor].Flip == UNFLIPPING)) {
|
||||
dbgSerial.println(""); dbgSerial.print("Stop Motor: ");
|
||||
if (axis[AltMotor].Flip == FLIPPING) {
|
||||
axis[AltMotor].Flip = FLIPPED; dbgSerial.print("FLIPPING");
|
||||
}
|
||||
else {
|
||||
axis[AltMotor].Flip = NORMAL; dbgSerial.print("NORMAl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckAltFlipReqd(void) {
|
||||
if (axis[AltMotor].ETXMotorState == ETXIdle) {
|
||||
if ((axis[AltMotor].Flip == FLIP) || (axis[AltMotor].Flip == UNFLIP)) {
|
||||
if (axis[AltMotor].Flip == FLIP) axis[AltMotor].Flip = FLIPPING;
|
||||
else axis[AltMotor].Flip = UNFLIPPING;
|
||||
// Rotate 180 degrees in RA
|
||||
if (axis[AzMotor].Target > ETX_CENTRE) axis[AzMotor].Target -= (axis[AzMotor].aVALUE >> 1);
|
||||
else axis[AzMotor].Target += (axis[AzMotor].aVALUE >> 1);
|
||||
axis[AzMotor].ETXMotorStatus |= (MOVEAXIS || MOVEHIGH);
|
||||
axis[AzMotor].ETXMotorStatus &= ~MOVESLEW;
|
||||
axis[AzMotor].MotorControl |= GoToHBX;
|
||||
CheckETXState(AzMotor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHbxValues(unsigned char Motor) {
|
||||
if (Motor == AzMotor)
|
||||
dbgSerial.println("AzMotor");
|
||||
else
|
||||
dbgSerial.println("AltMotor");
|
||||
|
||||
dbgSerial.print("Vanes "); dbgSerial.print(axis[Motor].Vanes);
|
||||
dbgSerial.print(", GbxRatio "); dbgSerial.print(axis[Motor].GbxRatio,4);
|
||||
dbgSerial.print(", XferRatio "); dbgSerial.print(axis[Motor].XferRatio,4);
|
||||
dbgSerial.print(", WormTeeth "); dbgSerial.println(axis[Motor].WormTeeth);
|
||||
dbgSerial.print("MeadeRatio "); dbgSerial.print(axis[Motor].MeadeRatio,6);
|
||||
dbgSerial.print(", MeadeSidereal "); dbgSerial.println(MeadeSidereal,4);
|
||||
|
||||
dbgSerial.print("aVALUE 0x"); dbgSerial.print(axis[Motor].aVALUE, HEX);
|
||||
dbgSerial.print(", bVALUE 0x"); dbgSerial.print(axis[Motor].bVALUE, HEX);
|
||||
dbgSerial.print(", PEC 0x"); dbgSerial.println(axis[Motor].PEC, HEX);
|
||||
|
||||
dbgSerial.print("BASERATE 0x"); dbgSerial.print(axis[Motor].BASERATE, HEX);
|
||||
dbgSerial.print(", SIDEREALRATE 0x"); dbgSerial.print(axis[Motor].SIDEREALRATE, HEX);
|
||||
dbgSerial.print(", SOLARRATE 0x"); dbgSerial.print(axis[Motor].SOLARRATE, HEX);
|
||||
dbgSerial.print(", LUNARRATE 0x"); dbgSerial.print(axis[Motor].LUNARRATE, HEX);
|
||||
dbgSerial.print(", DEGREERATE1 0x"); dbgSerial.println(axis[Motor].DEGREERATE1, HEX);
|
||||
|
||||
dbgSerial.print("One DEGREE 0x"); dbgSerial.println(axis[Motor].OneDegree, HEX);
|
||||
dbgSerial.println("");
|
||||
}
|
||||
|
||||
void PrintRatioValues(unsigned char scope) {
|
||||
int j;
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (j == 0)
|
||||
dbgSerial.print("AzMotor: ");
|
||||
else
|
||||
dbgSerial.print("AltMotor: ");
|
||||
dbgSerial.print("Vanes "); dbgSerial.print(ratio[scope][j].Vanes);
|
||||
dbgSerial.print(", GbxRatio "); dbgSerial.print(ratio[scope][j].GbxRatio,4);
|
||||
dbgSerial.print(", XferRatio "); dbgSerial.print(ratio[scope][j].XferRatio,4);
|
||||
dbgSerial.print(", WormTeeth "); dbgSerial.print(ratio[scope][j].WormTeeth);
|
||||
float r = (ratio[scope][j].Vanes * (float) 4 * ratio[scope][j].GbxRatio * ratio[scope][j].XferRatio * ratio[scope][j].WormTeeth) / (float) 1296000;
|
||||
dbgSerial.print(", MeadeRatio "); dbgSerial.println(r, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void HBXPrintStatus(unsigned char Motor) {
|
||||
axis[Motor].HBXCount = 0;
|
||||
if ((axis[Motor].Command != GetStatus) || (axis[Motor].HBXP1 | axis[Motor].HBXP2 | axis[Motor].HBXP3 | axis[Motor].HBXP4) || axis[Motor].PrintStatus0) {
|
||||
|
||||
/* dbgSerial.println("");
|
||||
dbgSerial.print("Motor: ");
|
||||
dbgSerial.print(axis_name[Motor]);
|
||||
dbgSerial.print(", Cmnd: ");
|
||||
dbgSerial.print(axis[Motor].Command, HEX);
|
||||
dbgSerial.print(" - ");
|
||||
*/
|
||||
switch (axis[Motor].Command) {
|
||||
case SpeedChnge:
|
||||
// dbgSerial.print("SpeedChnge ");
|
||||
axis[Motor].HBXCount = 3;
|
||||
break;
|
||||
case SpeedStart:
|
||||
// dbgSerial.print("SpeedStart ");
|
||||
axis[Motor].HBXCount = 3;
|
||||
break;
|
||||
case SetOffset:
|
||||
// dbgSerial.print("SetOffset ");
|
||||
axis[Motor].HBXCount = 4;
|
||||
break;
|
||||
case SetLEDI:
|
||||
// dbgSerial.print("SetLEDI ");
|
||||
axis[Motor].HBXCount = 1;
|
||||
break;
|
||||
case CalibrateLED:
|
||||
// dbgSerial.print("CalibrateLED ");
|
||||
break;
|
||||
case Stop:
|
||||
// dbgSerial.print("Stop ");
|
||||
break;
|
||||
case SlewReverse:
|
||||
// dbgSerial.print("SlewReverse ");
|
||||
break;
|
||||
case SlewForward:
|
||||
// dbgSerial.print("SlewForward ");
|
||||
break;
|
||||
case GetStatus:
|
||||
// dbgSerial.print("GetStatus ");
|
||||
axis[Motor].HBXCount = 4;
|
||||
break;
|
||||
case GetLEDI:
|
||||
// dbgSerial.print("GetLEDI ");
|
||||
axis[Motor].HBXCount = 1;
|
||||
break;
|
||||
case GetMotorType:
|
||||
// dbgSerial.print("GetMotorType ");
|
||||
axis[Motor].HBXP1 = axis[Motor].MotorType;
|
||||
axis[Motor].HBXCount = 1;
|
||||
break;
|
||||
case SleepHBX:
|
||||
// dbgSerial.print("SleepHBX ");
|
||||
break;
|
||||
default:
|
||||
dbgSerial.print("UNKNOWN ");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
if (axis[Motor].HBXCount != 0) {
|
||||
dbgSerial.print(", Data: ");
|
||||
dbgSerial.print(axis[Motor].HBXP1, HEX);
|
||||
if (axis[Motor].HBXCount >= 2) dbgSerial.print(", ");
|
||||
axis[Motor].HBXCount -= 1;
|
||||
}
|
||||
if (axis[Motor].HBXCount != 0) {
|
||||
dbgSerial.print(axis[Motor].HBXP2, HEX);
|
||||
if (axis[Motor].HBXCount >= 2) dbgSerial.print(", ");
|
||||
axis[Motor].HBXCount -= 1;
|
||||
}
|
||||
if (axis[Motor].HBXCount != 0) {
|
||||
dbgSerial.print(axis[Motor].HBXP3, HEX);
|
||||
if (axis[Motor].HBXCount >= 2) dbgSerial.print(", ");
|
||||
axis[Motor].HBXCount -= 1;
|
||||
}
|
||||
if (axis[Motor].HBXCount > 0) {
|
||||
dbgSerial.print(axis[Motor].HBXP4, HEX);
|
||||
axis[Motor].HBXCount -= 1;
|
||||
}
|
||||
dbgSerial.println("");
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG Protocol function definitions
|
||||
=================================
|
||||
*********************************************************/
|
||||
#pragma once
|
||||
|
||||
#define CR 0x0d
|
||||
#define LF 0x0a
|
||||
|
||||
#define HBXLEN 16
|
||||
#define HBXMASK HBXLEN-1
|
||||
|
||||
#define HCLRESETTIME 5 // Reset H2X Clock (mS)
|
||||
#define H2XRESETTIME 25 // Reset H2X bus
|
||||
#define BITTIME 100 // H2X clock ~200uS i.e 100us Low/High
|
||||
|
||||
#define STATUSDELAY 50 // H2X ETX status poll delay (mS)
|
||||
#define STATEDELAY 6.55 // H2X ETX state poll delay (mS)
|
||||
#define CMNDTIME 1 // H2X command delay (mS)
|
||||
#define STARTTIME 50 // H2X startup time for motors (mS)
|
||||
#define CLOCKTIMEOUT 50 // H2X Clock transition timeout (uS) (for monitor mode)
|
||||
#define MOTORDETECT 500 // H2X Detect Motor controller (mS)
|
||||
|
||||
uint8_t HDA = HDAAz; // Default
|
||||
uint8_t HCL = HCLAz; // Default
|
||||
|
||||
uint8_t pCommand;
|
||||
uint16_t pAzCount;
|
||||
uint16_t pAltCount;
|
||||
|
||||
unsigned char HBXBitTime = BITTIME;
|
||||
void TimerDelayuS(unsigned int);
|
||||
void TimerDelaymS(unsigned long);
|
||||
|
||||
bool HBXSendCommand(unsigned char, unsigned char);
|
||||
void HBXMotorReset(unsigned char);
|
||||
bool HBXStartSequence(unsigned char);
|
||||
void HBXSendByte(unsigned char, unsigned char);
|
||||
unsigned char HBXGetByte(unsigned char);
|
||||
void HBXSend2Bytes(unsigned char);
|
||||
void HBXSend3Bytes(unsigned char);
|
||||
void HBXGet3Bytes(unsigned char);
|
||||
|
||||
void HDAListen(uint8_t);
|
||||
void HDATalk(uint8_t);
|
||||
bool HBXReset(void);
|
||||
|
||||
long TwosComplement(long);
|
||||
|
||||
// Testing
|
||||
void HBXTestLoop(void);
|
||||
void HBXTest(void);
|
||||
bool HBXGet2Status(void);
|
|
@ -0,0 +1,334 @@
|
|||
/**@file*/
|
||||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
#include "Hardware.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "EQG2HBX.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXFileSystem.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
|
||||
/********************************************************
|
||||
HBX Comms related functions
|
||||
===========================
|
||||
*********************************************************/
|
||||
/**********************************************
|
||||
Multiple 1mS delay
|
||||
***********************************************/
|
||||
|
||||
void TimerDelaymS(unsigned long d) {
|
||||
delay(d);
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
Multiple 1uS delay
|
||||
***********************************************/
|
||||
|
||||
void TimerDelayuS(unsigned int d) {
|
||||
delayMicroseconds(d);
|
||||
}
|
||||
|
||||
// HBX Attempt to reset
|
||||
// --------------------
|
||||
void HBXMotorReset(unsigned char Motor)
|
||||
{
|
||||
if (Motor == AzMotor) {HCL = HCLAz; HDA = HDAAz;}
|
||||
else {HCL = HCLAlt; HDA = HDAAlt;}
|
||||
/*
|
||||
int i;
|
||||
|
||||
// Write LOW
|
||||
HDATalk(Motor);
|
||||
digitalWrite(HDA1, LOW);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
|
||||
else digitalWrite(HCL2, LOW);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
|
||||
else digitalWrite(HCL2, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
}
|
||||
|
||||
// Write HIGH
|
||||
digitalWrite(HDA1, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
|
||||
else digitalWrite(HCL2, LOW);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
|
||||
else digitalWrite(HCL2, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
}
|
||||
|
||||
// Read, and discard, a byte
|
||||
HDAListen(HDA);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
|
||||
else digitalWrite(HCL2, LOW);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
|
||||
else digitalWrite(HCL2, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
}
|
||||
*/
|
||||
|
||||
// Force Clock High, Low, High for reset, time ~1.25s
|
||||
HCLTalk(Motor);
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelaymS(MOTORDETECT);
|
||||
digitalWrite(HCL, LOW);
|
||||
TimerDelaymS(MOTORDETECT);
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelaymS(MOTORDETECT >> 1);
|
||||
}
|
||||
|
||||
// HBX transmission functions
|
||||
// ==========================
|
||||
|
||||
// HBX Send a command
|
||||
// ------------------
|
||||
bool HBXSendCommand(unsigned char Command, unsigned char Motor) {
|
||||
|
||||
pCommand = Command;
|
||||
if (Command != GetStatus){
|
||||
dbgSerial.println("");dbgSerial.print("+++ ");dbgSerial.print(Motor);
|
||||
}
|
||||
axis[Motor].Command = Command;
|
||||
|
||||
// Select the interface
|
||||
if (Motor == MotorAz) {HDA = HDAAz;HCL = HCLAz;}
|
||||
else {HDA = HDAAlt;HCL = HCLAlt;}
|
||||
|
||||
// Send the start sequence
|
||||
// -----------------------
|
||||
if (HBXStartSequence(Motor)) {
|
||||
// Send the command byte
|
||||
// ---------------------
|
||||
HBXSendByte(Command, Motor);
|
||||
return(true);
|
||||
}
|
||||
else {
|
||||
HDAListen(HDA); // Set data inbound
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
// HBX Initiate start sequence
|
||||
// ---------------------------
|
||||
bool HBXStartSequence(unsigned char Motor) {
|
||||
if (Motor == AzMotor) {HCL = HCLAz; HDA = HDAAz;}
|
||||
else if (Motor == AltMotor) {HCL = HCLAlt; HDA = HDAAlt;}
|
||||
else {HCL = HCLAux; HDA = HDAAux;}
|
||||
|
||||
// 1. HDA as input, Clock as output
|
||||
HDAListen(HDA);
|
||||
HCLTalk(HCL);
|
||||
// 2. Set clock low
|
||||
digitalWrite(HCL, LOW);
|
||||
TimerDelayuS(HBXBitTime >> 1); // 1/2 bit-time
|
||||
// 3. Wait for data low (HDA = 0) by MC, or timeout
|
||||
H2XStart = micros();
|
||||
do {
|
||||
H2XTimer = micros() - H2XStart;
|
||||
} while ((digitalRead(HDA) == 1) && (H2XTimer < (HBXBitTime << 3)));
|
||||
TimerDelayuS((HBXBitTime >> 5)); // 1/32 bit-time delay, in case of data line glitch
|
||||
// 4. Re-read data line, check if (data low) or (MC timeout)
|
||||
if ((digitalRead(HDA) == 1) || (H2XTimer >= (HBXBitTime << 3))) {
|
||||
digitalWrite(HCL, HIGH);
|
||||
return(false); // error exit if no response from Motor
|
||||
}
|
||||
// 5. Set clock high if data low occurred (i.e. MC acknowledged clock low)
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelayuS(HBXBitTime >> 1);
|
||||
// 6. Wait for data line release (HDA = 1) by MC, or timeout
|
||||
H2XStart = micros();
|
||||
do {
|
||||
H2XTimer = micros() - H2XStart;
|
||||
} while ((digitalRead(HDA) == 0) && (H2XTimer < (HBXBitTime << 3)));
|
||||
TimerDelayuS(HBXBitTime); // Wait one bit-time, in case of success
|
||||
// 7. Check timeout for data line released or no response from MC
|
||||
if (H2XTimer >= (HBXBitTime << 3)) {
|
||||
return(false); // Error Exit if no response from MC
|
||||
}
|
||||
return(true); // Success
|
||||
}
|
||||
|
||||
// HBX Send a single byte
|
||||
// ----------------------
|
||||
void HBXSendByte(unsigned char databyte, unsigned char Motor) {
|
||||
|
||||
unsigned char mask;
|
||||
if (Motor == AzMotor) {HCL = HCLAz; HDA = HDAAz;}
|
||||
else if (Motor == AltMotor) {HCL = HCLAlt; HDA = HDAAlt;}
|
||||
else {HCL = HCLAux; HDA = HDAAux;}
|
||||
|
||||
if (axis[Motor].Command != GetStatus) {
|
||||
dbgSerial.print("-> "); dbgSerial.print(databyte, HEX);
|
||||
}
|
||||
|
||||
HDATalk(HDA); // HDA as output
|
||||
axis[Motor].HBXBitCount = 8; // 8bits to go
|
||||
mask = 0x80; // MSB first
|
||||
// Clock was set high before entry
|
||||
TimerDelayuS(HBXBitTime);
|
||||
do {
|
||||
axis[Motor].HBXBitCount -= 1;
|
||||
// Set data bit
|
||||
if (databyte & mask) digitalWrite(HDA, HIGH);
|
||||
else digitalWrite(HDA, LOW);
|
||||
TimerDelayuS(HBXBitTime >> 1); // Let data stabilise
|
||||
mask = mask >> 1; // Next data bit
|
||||
// Set clock low
|
||||
digitalWrite(HCL, LOW);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
// Set clock high
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelayuS(HBXBitTime-(HBXBitTime >> 1)); // Data is written DSTABLE before clock low
|
||||
// for 8 bits
|
||||
} while (axis[Motor].HBXBitCount);
|
||||
TimerDelayuS(HBXBitTime >> 1); // Last high clock
|
||||
HDAListen(HDA); // Release data pin
|
||||
TimerDelayuS(HBXBitTime);
|
||||
}
|
||||
|
||||
// HBX Send two bytes in sequence
|
||||
// ------------------------------
|
||||
void HBXSend2Bytes(unsigned char Motor) {
|
||||
HBXSendByte(axis[Motor].HBXP1, Motor);
|
||||
HBXSendByte(axis[Motor].HBXP2, Motor);
|
||||
if (pCommand != GetStatus) dbgSerial.println("");
|
||||
}
|
||||
|
||||
// HBX Send three bytes in sequence
|
||||
// --------------------------------
|
||||
void HBXSend3Bytes(unsigned char Motor) {
|
||||
HBXSendByte(axis[Motor].HBXP1, Motor);
|
||||
HBXSendByte(axis[Motor].HBXP2, Motor);
|
||||
HBXSendByte(axis[Motor].HBXP3, Motor);
|
||||
if (pCommand != GetStatus) dbgSerial.println("");
|
||||
}
|
||||
|
||||
// HBX Get a single byte
|
||||
// ----------------------
|
||||
unsigned char HBXGetByte(unsigned char Motor) {
|
||||
|
||||
if (Motor == AzMotor) {HCL = HCLAz; HDA = HDAAz;}
|
||||
else if (Motor == AltMotor) {HCL = HCLAlt; HDA = HDAAlt;}
|
||||
else {HCL = HCLAux; HDA = HDAAux;}
|
||||
|
||||
// HDA as input
|
||||
HDAListen(HDA);
|
||||
axis[Motor].HBXBitCount = 8;
|
||||
axis[Motor].HBXData = 0;
|
||||
// Clock was set high before entry
|
||||
while (axis[Motor].HBXBitCount) {
|
||||
// Set clock low
|
||||
digitalWrite(HCL, LOW);
|
||||
TimerDelayuS(HBXBitTime >> 1);
|
||||
// Read data bit
|
||||
axis[Motor].HBXData = axis[Motor].HBXData << 1; // Shift previous bit
|
||||
if (digitalRead(HDA)) axis[Motor].HBXData |= 0x01; // Read next bit
|
||||
axis[Motor].HBXBitCount--; // Need eight bits
|
||||
TimerDelayuS(HBXBitTime-(HBXBitTime >> 1)); // Wait for low time
|
||||
// Set clock high
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
}
|
||||
TimerDelayuS(HBXBitTime);
|
||||
if (axis[Motor].Command != GetStatus) {
|
||||
dbgSerial.print("<- "); dbgSerial.print(axis[Motor].HBXData, HEX);
|
||||
}
|
||||
// Return data byte
|
||||
axis[Motor].HBXCount = 1;
|
||||
return (axis[Motor].HBXData);
|
||||
}
|
||||
|
||||
// HBX Get the status bytes (25 bits)
|
||||
// ----------------------------------
|
||||
void HBXGet3Bytes(unsigned char Motor) {
|
||||
|
||||
axis[Motor].HBXP1 = HBXGetByte(Motor);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
axis[Motor].HBXP2 = HBXGetByte(Motor);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
axis[Motor].HBXP3 = HBXGetByte(Motor);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
axis[Motor].HBXP4 = 0;
|
||||
|
||||
// Read 'byte4' = error bit
|
||||
// ------------------------
|
||||
digitalWrite(HCL, LOW);
|
||||
TimerDelayuS(HBXBitTime >> 1);
|
||||
axis[Motor].HBXP4 |= digitalRead(HDA); // Read the battery error bit
|
||||
TimerDelayuS(HBXBitTime-(HBXBitTime >> 1));
|
||||
digitalWrite(HCL, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
if (axis[Motor].Command != GetStatus) {
|
||||
dbgSerial.print("- "); dbgSerial.print(axis[Motor].HBXP4, HEX);
|
||||
}
|
||||
axis[Motor].HBXCount = 4;
|
||||
if (pCommand != GetStatus) dbgSerial.println("");
|
||||
}
|
||||
|
||||
// H2X Low level Functions
|
||||
// -----------------------
|
||||
void HDAListen(uint8_t HDA) {
|
||||
// digitalWrite(HDA, HIGH);
|
||||
pinMode(HDA, H2C_INPUT);
|
||||
}
|
||||
void HDAFloat(uint8_t HDA) {
|
||||
pinMode(HDA, H2C_INPUT);
|
||||
}
|
||||
void HDATalk(uint8_t HDA) {
|
||||
digitalWrite(HDA, HIGH);
|
||||
pinMode(HDA, H2C_OUTPUT);
|
||||
}
|
||||
void HCLListen(uint8_t HCL) {
|
||||
// digitalWrite(HCL, HIGH);
|
||||
pinMode(HCL, H2C_INPUTPU);
|
||||
}
|
||||
void HCLFloat(uint8_t HCL) {
|
||||
pinMode(HCL, H2C_INPUT);
|
||||
}
|
||||
void HCLTalk(uint8_t HCL) {
|
||||
digitalWrite(HCL, HIGH);
|
||||
pinMode(HCL, H2C_OUTPUT);
|
||||
}
|
||||
|
||||
bool HBXReset(void) {
|
||||
int ClockCount = 0;
|
||||
|
||||
HCLTalk(HCLAz); // Set clock high
|
||||
HCLTalk(HCLAlt); // Set clock high
|
||||
HCLTalk(HCLAux); // Set clock high
|
||||
HDAListen(HDAAz); // Set common data inbound
|
||||
TimerDelayuS(HBXBitTime);
|
||||
|
||||
// Data should be high
|
||||
while ((!digitalRead(HDA)) && (ClockCount < 25)) {
|
||||
digitalWrite(HCLAux, LOW);
|
||||
digitalWrite(HCLAz, LOW);
|
||||
digitalWrite(HCLAlt, LOW);
|
||||
TimerDelaymS(HCLRESETTIME);
|
||||
digitalWrite(HCLAux, HIGH);
|
||||
digitalWrite(HCLAz, HIGH);
|
||||
digitalWrite(HCLAlt, HIGH);
|
||||
TimerDelayuS(HBXBitTime);
|
||||
ClockCount += 1;
|
||||
}
|
||||
if (ClockCount >= 25) return(false);
|
||||
else return(true);
|
||||
}
|
||||
|
||||
long TwosComplement(long p) { // Calculate 2s complement
|
||||
long q;
|
||||
q = ~p; // Bitwise invert
|
||||
q = q + 1; // +1
|
||||
return q;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
/**************************************************************
|
||||
* SPIFFS filesystem
|
||||
* Only invoked in STA mode
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <SPIFFSEditor.h>
|
||||
|
||||
#define FORMAT_SPIFFS_IF_FAILED true
|
|
@ -0,0 +1,108 @@
|
|||
/**@file*/
|
||||
// SPIFFS file system
|
||||
#include "Hardware.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "EQG2HBX.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXFileSystem.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
|
||||
Serial.printf("Listing directory: %s\r\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if (!root) {
|
||||
Serial.println("- failed to open directory");
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
Serial.println(" - not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if (levels) {
|
||||
listDir(fs, file.name(), levels - 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print("\tSIZE: ");
|
||||
Serial.println(file.size());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
|
||||
void readFile(fs::FS &fs, const char * path) {
|
||||
Serial.printf("Reading file: %s\r\n", path);
|
||||
|
||||
File file = fs.open(path);
|
||||
if (!file || file.isDirectory()) {
|
||||
Serial.println("- failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("- read from file:");
|
||||
while (file.available()) {
|
||||
Serial.write(file.read());
|
||||
}
|
||||
}
|
||||
|
||||
void writeFile(fs::FS &fs, const char * path, const char * message) {
|
||||
Serial.printf("Writing file: %s\r\n", path);
|
||||
|
||||
File file = fs.open(path, FILE_WRITE);
|
||||
if (!file) {
|
||||
Serial.println("- failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
if (file.print(message)) {
|
||||
Serial.println("- file written");
|
||||
}
|
||||
else {
|
||||
Serial.println("- frite failed");
|
||||
}
|
||||
}
|
||||
|
||||
void appendFile(fs::FS &fs, const char * path, const char * message) {
|
||||
Serial.printf("Appending to file: %s\r\n", path);
|
||||
|
||||
File file = fs.open(path, FILE_APPEND);
|
||||
if (!file) {
|
||||
Serial.println("- failed to open file for appending");
|
||||
return;
|
||||
}
|
||||
if (file.print(message)) {
|
||||
Serial.println("- message appended");
|
||||
}
|
||||
else {
|
||||
Serial.println("- append failed");
|
||||
}
|
||||
}
|
||||
|
||||
void renameFile(fs::FS &fs, const char * path1, const char * path2) {
|
||||
Serial.printf("Renaming file %s to %s\r\n", path1, path2);
|
||||
if (fs.rename(path1, path2)) {
|
||||
Serial.println("- file renamed");
|
||||
}
|
||||
else {
|
||||
Serial.println("- rename failed");
|
||||
}
|
||||
}
|
||||
|
||||
void deleteFile(fs::FS &fs, const char * path) {
|
||||
Serial.printf("Deleting file: %s\r\n", path);
|
||||
if (fs.remove(path)) {
|
||||
Serial.println("- file deleted");
|
||||
}
|
||||
else {
|
||||
Serial.println("- delete failed");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
|
||||
/*
|
||||
* Copyright 2017, 2018, 2020 John Archbold
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
EQG Serial WiFi
|
||||
===============
|
||||
*********************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <AsyncUDP.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Update.h>
|
||||
#include <esp_now.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
/**************************************************************
|
||||
* WiFi communications buffers and pointers
|
||||
* WiFi variables
|
||||
**************************************************************/
|
||||
|
||||
uint8_t smac[] = { 0x5C, 0xCF, 0x7F, 0x88, 0x88, 0x88 }; // Hopefully :) Unique Espressif mac
|
||||
uint8_t mmac[] = { 0x5C, 0xCF, 0x7F, 0x00, 0x00, 0x00 }; // Master mac address
|
||||
const uint8_t WIFI_CHANNEL = 4;
|
||||
|
||||
String ssid; // char ssid[64] = "EQMODWiFi";
|
||||
String pass; // char pass[64] = "CShillit0";
|
||||
|
||||
const char* http_username = "admin";
|
||||
const char* http_password = "eqmod";
|
||||
// flag to use from web update to reboot the ESP
|
||||
bool shouldReboot = false;
|
||||
bool loginValid = false;
|
||||
|
||||
IPAddress ip(192, 168, 88, 1);
|
||||
IPAddress gateway(192, 168, 88, 1);
|
||||
IPAddress netmask(255, 255, 255, 0);
|
||||
|
||||
/**************************************************************
|
||||
* WiFi WebServer
|
||||
* Only invoked in STA mode
|
||||
*/
|
||||
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws
|
||||
AsyncEventSource events("/events"); // event source (Server-Sent events)
|
||||
|
||||
/**************************************************************
|
||||
* WiFi ESP_NOW
|
||||
*/
|
||||
esp_now_peer_info serial_peer;
|
||||
|
||||
/**************************************************************
|
||||
* WiFi UDP
|
||||
*/
|
||||
WiFiUDP udp;
|
||||
IPAddress remoteIp;
|
||||
const int localUdpPort = 11880;
|
||||
|
||||
/**************************************************************
|
||||
* WiFi Data Buffers
|
||||
*/
|
||||
struct __attribute__((packed)) DataStruct {
|
||||
char text[ESP_NOW_MAX_DATA_LEN];
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
DataStruct sendWiFi;
|
||||
DataStruct recvWiFi;
|
||||
uint8_t sendWiFi8[sizeof(sendWiFi)];
|
||||
uint8_t recvWiFi8[sizeof(recvWiFi)];
|
||||
|
||||
/**************************************************************
|
||||
* WiFi EQMOD virtualization
|
||||
*/
|
||||
#define EQxTimeout 10
|
||||
#define EQxSize ESP_NOW_MAX_DATA_LEN-1
|
||||
|
||||
uint8_t RxD;
|
||||
uint8_t TxD;
|
||||
uint8_t TxDIndex;
|
||||
|
||||
unsigned long RxTimeout;
|
||||
unsigned long WiFiTimeout;
|
||||
unsigned long LastmS;
|
||||
unsigned long CheckmS = 1000;
|
||||
bool Connected = false;
|
||||
bool dataSending = false;
|
||||
bool waitingForReply = false;
|
||||
|
||||
unsigned long TxDuS;
|
||||
unsigned long AckuS;
|
||||
unsigned long RxDuS;
|
||||
|
||||
unsigned long LastLEDmS;
|
||||
unsigned long FastLEDmS = 200;
|
||||
unsigned long SlowLEDmS = 800;
|
||||
unsigned long BlinkmS = SlowLEDmS;
|
||||
unsigned long SavedBlinkmS = SlowLEDmS;
|
||||
|
||||
bool UDPFlag = false;
|
||||
bool APFlag = false;
|
||||
bool SerialFlag = false;
|
||||
|
||||
void HBXWiFiSetup();
|
||||
bool HBXCheckRx();
|
||||
void HBXCheckTx();
|
||||
void InitESPNow();
|
||||
void recvCallBack(const uint8_t*, const uint8_t* , int );
|
||||
void sendData(const esp_now_peer_info_t* );
|
||||
void sendCallBack(const uint8_t* , esp_now_send_status_t );
|
||||
void putRxDataIntoMountInputBuffer(void);
|
||||
void getTxDataFromMountOutputBuffer(void);
|
|
@ -0,0 +1,509 @@
|
|||
/**@file*/
|
||||
// HBXSerialServer.ino
|
||||
// https://esp-idf.readthedocs.io/en/latest/api-reference/wifi/esp_now.html
|
||||
#include "Hardware.h"
|
||||
#include "ETXProtocol.h"
|
||||
#include "EQGProtocol.h"
|
||||
#include "EQG2HBX.h"
|
||||
#include "HBXComms.h"
|
||||
#include "HBXFileSystem.h"
|
||||
#include "HBXWiFiServer.h"
|
||||
#include <FS.h> // Include the SPIFFS library
|
||||
|
||||
// Init ESP Now with fallback
|
||||
void InitESPNow() {
|
||||
WiFi.disconnect();
|
||||
if (esp_now_init() == ESP_OK) {
|
||||
dbgSerial.println("ESPNow Init Success");
|
||||
}
|
||||
else {
|
||||
dbgSerial.println("ESPNow Init Failed");
|
||||
// Retry InitESPNow, add a counter and then restart?
|
||||
// InitESPNow();
|
||||
// or Simply Restart
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle ESP_NOW WiFi data
|
||||
// Data in recvWiFi.text, length recvWiFi.len
|
||||
void recvCallBack(const uint8_t *senderMac, const uint8_t *incomingData, int len) {
|
||||
|
||||
// Get data from WiFi buffer
|
||||
memcpy(&recvWiFi.text, incomingData, len); // Receive data from EQMOD Tx
|
||||
recvWiFi.text[len] = 0; // Null terminate
|
||||
recvWiFi.len = len;
|
||||
|
||||
// Check if serial device is requesting restart
|
||||
if ((len == 20) && ((strncmp(recvWiFi.text, "Mount, please reply", 15) == 0))) {
|
||||
// Capture the serial device mac address
|
||||
for (byte n = 0; n < ESP_NOW_ETH_ALEN; n++) {
|
||||
serial_peer.peer_addr[n] = senderMac[n];
|
||||
}
|
||||
// Discard data from reconnect request, clear flags
|
||||
recvWiFi.len = 0;
|
||||
Connected = false;
|
||||
dataSending = false;
|
||||
// Reply to reconnect request
|
||||
strcpy(sendWiFi.text, "EQMOD WiFi Mount V1.0\n");
|
||||
sendWiFi.len = sizeof("EQMOD WiFi Mount V1.0\n");
|
||||
dbgSerial.println("Reconnecting");
|
||||
sendData(&serial_peer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Send data to ESP_NOW
|
||||
void sendData(const esp_now_peer_info_t* s_peer) {
|
||||
// If first time, create a peer2peer connection with the sender mac address
|
||||
if (!Connected) {
|
||||
esp_now_add_peer(s_peer); // Only one paired device - the first one to respond
|
||||
}
|
||||
|
||||
// Send data, if not waiting for previous send to complete
|
||||
if (!dataSending) {
|
||||
memcpy(sendWiFi8, &sendWiFi, sendWiFi.len); // Need to satisfy esp_now
|
||||
esp_now_send(serial_peer.peer_addr, sendWiFi8, sendWiFi.len);
|
||||
dataSending = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get Send data status
|
||||
void sendCallBack(const uint8_t* mac, esp_now_send_status_t sendStatus) {
|
||||
if (sendStatus == 0) {
|
||||
sendWiFi.len = 0; // Data successfully sent
|
||||
Connected = true;
|
||||
dataSending = false;
|
||||
}
|
||||
// Do some error checking?
|
||||
}
|
||||
|
||||
// Put received WiFi (UDP/ESP_NOW) data into the mount input data buffer for processing
|
||||
// Data in recvWiFi.text, length recvWiFi.len
|
||||
void putRxDataIntoMountInputBuffer(void) {
|
||||
uint8_t n;
|
||||
n = 0;
|
||||
while (n < recvWiFi.len) {
|
||||
EQGRxBuffer[EQGRxiPtr++] = recvWiFi.text[n];
|
||||
EQGRxiPtr &= EQGMASK;
|
||||
n += 1;
|
||||
}
|
||||
recvWiFi.len = 0;
|
||||
}
|
||||
|
||||
// Get mount data to send to WiFi (UDP/NOW) into WiFi buffer
|
||||
// Data in sendWiFi.text, length sendWiFi.len
|
||||
void getTxDataFromMountOutputBuffer(void) {
|
||||
while (EQGTxoPtr != EQGTxiPtr) {
|
||||
if ((EQGTxBuffer[EQGTxoPtr] != CR) && (EQGTxBuffer[EQGTxoPtr] != LF))
|
||||
dbgSerial.write(EQGTxBuffer[EQGTxoPtr]);
|
||||
else dbgSerial.write('.');
|
||||
sendWiFi.text[TxDIndex++] = EQGTxBuffer[EQGTxoPtr++];
|
||||
EQGTxoPtr &= EQGMASK;
|
||||
}
|
||||
// Send when a CR is detected
|
||||
if (sendWiFi.text[TxDIndex - 1] == 0x0d) {
|
||||
sendWiFi.text[TxDIndex] = 0;
|
||||
sendWiFi.len = TxDIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Webserver functions for ssid, pass, telescope etc
|
||||
// =================================================
|
||||
|
||||
void onRequest(AsyncWebServerRequest *request){
|
||||
//Handle Unknown Request
|
||||
request->send(404, "text/plain", "The content you are looking for was not found.");
|
||||
}
|
||||
|
||||
void onBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
|
||||
if (!index) {
|
||||
dbgSerial.printf("BodyStart: %u B\n", total);
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
dbgSerial.write(data[i]);
|
||||
}
|
||||
if (index + len == total) {
|
||||
dbgSerial.printf("BodyEnd: %u B\n", total);
|
||||
}
|
||||
}
|
||||
|
||||
void onUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||
if (!index) {
|
||||
dbgSerial.printf("UploadStart: %s\n", filename.c_str());
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
dbgSerial.write(data[i]);
|
||||
}
|
||||
if (final) {
|
||||
dbgSerial.printf("UploadEnd: %s, %u B\n", filename.c_str(), index + len);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncServerResponseSetup(void) {
|
||||
|
||||
// respond to GET requests on URL /scan
|
||||
//First request will return 0 results unless you start scan from somewhere else (loop/setup)
|
||||
//Do not request more often than 3-5 seconds
|
||||
|
||||
server.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
String json = "[";
|
||||
int n = WiFi.scanComplete();
|
||||
if(n == -2){
|
||||
WiFi.scanNetworks(true);
|
||||
} else if(n){
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if(i) json += ",";
|
||||
json += "{";
|
||||
json += "\"rssi\":"+String(WiFi.RSSI(i));
|
||||
json += ",\"ssid\":\""+WiFi.SSID(i)+"\"";
|
||||
json += ",\"bssid\":\""+WiFi.BSSIDstr(i)+"\"";
|
||||
json += ",\"channel\":"+String(WiFi.channel(i));
|
||||
json += ",\"secure\":"+String(WiFi.encryptionType(i));
|
||||
// json += ",\"hidden\":"+String(WiFi.isHidden(i)?"true":"false");
|
||||
json += "}\r\n";
|
||||
}
|
||||
WiFi.scanDelete();
|
||||
if(WiFi.scanComplete() == -2){
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
}
|
||||
json += "]";
|
||||
request->send(200, "application/json", json);
|
||||
json = String();
|
||||
});
|
||||
|
||||
// upload a file to /upload
|
||||
server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||
request->send(200);
|
||||
}, onUpload);
|
||||
|
||||
// send /index.htm file when /index is requested
|
||||
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
|
||||
request->send(SPIFFS, "/www/index.htm");
|
||||
});
|
||||
|
||||
// send /settings.htm file when /settings is requested
|
||||
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
request->send(SPIFFS, "/www/settings.htm");
|
||||
int paramsNr = request->params();
|
||||
dbgSerial.print("Number of settings parameters: "); dbgSerial.println(paramsNr);
|
||||
if (paramsNr) {
|
||||
for (int i = 0; i < paramsNr; i++) {
|
||||
AsyncWebParameter* p = request->getParam(i);
|
||||
dbgSerial.print("Param name: "); dbgSerial.print(p->name());
|
||||
dbgSerial.print(", value: "); dbgSerial.println(p->value());
|
||||
if ((p->name()) == "ssid")
|
||||
ssid = (p->value());
|
||||
if ((p->name()) == "pass")
|
||||
pass = (p->value());
|
||||
if ((p->name()) == "scope")
|
||||
strcpy(scope, (p->value()).c_str());
|
||||
}
|
||||
|
||||
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
|
||||
|
||||
dbgSerial.print("Original - ssid: "); dbgSerial.print(preferences.getString("STA_SSID"));
|
||||
dbgSerial.print(", pass: "); dbgSerial.print(preferences.getString("STA_PASS"));
|
||||
dbgSerial.print(", Telescope: "); dbgSerial.println(preferences.getString("TELESCOPE"));
|
||||
|
||||
if (strlen(ssid.c_str()) != 0) preferences.putString("STA_SSID", ssid);
|
||||
if (strlen(pass.c_str()) != 0) preferences.putString("STA_PASS", pass);
|
||||
if (strlen(scope) != 0) preferences.putString("TELESCOPE", scope);
|
||||
|
||||
dbgSerial.print("Updated - ssid: "); dbgSerial.print(preferences.getString("STA_SSID"));
|
||||
dbgSerial.print(", pass: "); dbgSerial.print(preferences.getString("STA_PASS"));
|
||||
dbgSerial.print(", Telescope: "); dbgSerial.println(preferences.getString("TELESCOPE"));
|
||||
preferences.end();
|
||||
}
|
||||
});
|
||||
|
||||
// HTTP basic authentication
|
||||
server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
dbgSerial.print("B4 http_username: ");
|
||||
dbgSerial.print(http_username);
|
||||
dbgSerial.print(", http_password: ");
|
||||
dbgSerial.println(http_password);
|
||||
|
||||
if(!request->authenticate(http_username, http_password))
|
||||
return request->requestAuthentication();
|
||||
else {
|
||||
dbgSerial.print("http_username: ");
|
||||
dbgSerial.print(http_username);
|
||||
dbgSerial.print(", http_password: ");
|
||||
dbgSerial.println(http_password);
|
||||
}
|
||||
request->send(200, "text/plain", "Login Success!");
|
||||
loginValid = true;
|
||||
});
|
||||
|
||||
// Simple Firmware Update Form
|
||||
// send /update.htm file when /index is requested
|
||||
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
if (loginValid == true) {
|
||||
request->send(SPIFFS, "/update.htm");
|
||||
}
|
||||
else {
|
||||
request->send(200, "text/plain", "Before you can update firmware, Please Login");
|
||||
}
|
||||
});
|
||||
|
||||
// Process POST from Update Form
|
||||
server.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||
shouldReboot = !Update.hasError();
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot?"OK":"FAIL");
|
||||
response->addHeader("Connection", "close");
|
||||
request->send(response);
|
||||
},[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||
if(!index){
|
||||
dbgSerial.printf("Update Start: %s\n", filename.c_str());
|
||||
|
||||
// Update.runAsync(true);
|
||||
// if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) {
|
||||
if (!Update.begin(0x140000)) {
|
||||
Update.printError(dbgSerial);
|
||||
}
|
||||
}
|
||||
if(!Update.hasError()){
|
||||
if(Update.write(data, len) != len){
|
||||
Update.printError(dbgSerial);
|
||||
}
|
||||
}
|
||||
if(final){
|
||||
if(Update.end(true)){
|
||||
dbgSerial.printf("Update Success: %uB\n", index+len);
|
||||
} else {
|
||||
Update.printError(dbgSerial);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void browseService(const char * service, const char * proto) {
|
||||
Serial.printf("Browsing for service _%s._%s.local. ... ", service, proto);
|
||||
int n = MDNS.queryService(service, proto);
|
||||
if (n == 0) {
|
||||
Serial.println("no services found");
|
||||
}
|
||||
else {
|
||||
Serial.print(n);
|
||||
Serial.println(" service(s) found");
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// Print details for each service found
|
||||
Serial.print(" ");
|
||||
Serial.print(i + 1);
|
||||
Serial.print(": ");
|
||||
Serial.print(MDNS.hostname(i));
|
||||
Serial.print(" (");
|
||||
Serial.print(MDNS.IP(i));
|
||||
Serial.print(":");
|
||||
Serial.print(MDNS.port(i));
|
||||
Serial.println(")");
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
|
||||
void HBXWiFiSetup() {
|
||||
|
||||
// TODO
|
||||
// Read from EEPROM
|
||||
// ESPNOW
|
||||
|
||||
UDPFlag = false;
|
||||
#ifdef SelectUDP
|
||||
UDPFlag = true; // Either UDP or ESPNOW
|
||||
#endif
|
||||
APFlag = false;
|
||||
#ifdef SelectAP
|
||||
APFlag = true; // Either AP or STA
|
||||
#endif
|
||||
|
||||
if (APFlag) {
|
||||
// AP mode device connects directly to EQMODWiFi (no router)
|
||||
// For AP mode: UDP2Serial: This ESP assigns IP addresses
|
||||
// For AP mode: ESP IP is always 192.168.88.1 (set above)
|
||||
|
||||
dbgSerial.println("EQMODWiFi Access Point Mode");
|
||||
// Check preferences for ssid, pass
|
||||
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
|
||||
if (preferences.getString("AP_SSID", "none") == "none")
|
||||
preferences.putString("AP_SSID", "EQGWiFi"); // Default
|
||||
if (preferences.getString("AP_PASS", "none") == "none")
|
||||
preferences.putString("AP_PASS", "EQG2HBXPcl"); // Default
|
||||
ssid = preferences.getString("AP_SSID", "none");
|
||||
pass = preferences.getString("AP_PASS", "none");
|
||||
preferences.end();
|
||||
|
||||
WiFi.persistent(false);
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(ssid.c_str(), pass.c_str()); // softAP ssid, pass
|
||||
delay(2000); // Espressif wifi bug needs this
|
||||
WiFi.softAPConfig(ip, gateway, netmask); // softAP ip
|
||||
dbgSerial.print("SoftAP IP address: "); dbgSerial.println(WiFi.softAPIP());
|
||||
}
|
||||
else {
|
||||
// STA mode EQMODWiFi connects to network router and gets an IP
|
||||
// For STA mode: Host software must detect that IP
|
||||
// For STA mode: UDP2Serial router network assigns IP address
|
||||
// For STA mode: Start webserver, mDNS and accept changes to ssid, pass, Telescope etc
|
||||
|
||||
dbgSerial.println("EQMODWiFi Station Mode");
|
||||
// Check preferences for ssid, pass
|
||||
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
|
||||
preferences.putString("STA_SSID", "bunyas_g");
|
||||
preferences.putString("STA_PASS", "WindyRidge137");
|
||||
if (preferences.getString("STA_SSID", "none") == "none")
|
||||
preferences.putString("STA_SSID", "EQGnet"); // Default Home Network
|
||||
if (preferences.getString("STA_PASS", "none") == "none")
|
||||
preferences.putString("STA_PASS", "EQGconnect");
|
||||
ssid = preferences.getString("STA_SSID", "none");
|
||||
pass = preferences.getString("STA_PASS", "none");
|
||||
preferences.end();
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect();
|
||||
WiFi.begin(ssid.c_str(), pass.c_str());
|
||||
int i = 0;
|
||||
while ((WiFi.status() != WL_CONNECTED) && (i++ < 50)) {
|
||||
delay(1000);
|
||||
dbgSerial.print(i); dbgSerial.print(", ssid: "); dbgSerial.print(ssid.c_str()); dbgSerial.print(", pass: "); dbgSerial.println(pass.c_str());
|
||||
}
|
||||
if (i >= 50) {
|
||||
WiFi.begin("EQGnet", "EQGconnect");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
dbgSerial.print("!");
|
||||
}
|
||||
}
|
||||
dbgSerial.print("ssid: "); dbgSerial.println(ssid.c_str());
|
||||
dbgSerial.print("pass: "); dbgSerial.println(pass.c_str());
|
||||
dbgSerial.print("IP: "); dbgSerial.println(WiFi.localIP().toString().c_str());
|
||||
dbgSerial.println(" connected");
|
||||
if (!MDNS.begin("eqmodwifi")) {
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
Serial.println("mDNS responder started");
|
||||
dbgSerial.print("ssid: "); dbgSerial.println(ssid.c_str());
|
||||
dbgSerial.print("pass: "); dbgSerial.println(pass.c_str());
|
||||
dbgSerial.print("IP: "); dbgSerial.println(WiFi.softAPIP().toString().c_str());
|
||||
// Load 'server.on' responses
|
||||
AsyncServerResponseSetup();
|
||||
WiFi.scanNetworks();
|
||||
dbgSerial.print("ssid: "); dbgSerial.println(ssid.c_str());
|
||||
dbgSerial.print("pass: "); dbgSerial.println(pass.c_str());
|
||||
dbgSerial.print("IP: "); dbgSerial.println(WiFi.softAPIP().toString().c_str());
|
||||
// attach filesystem root at URL /fs
|
||||
if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
|
||||
dbgSerial.println("SPIFFS Mount Failed, SPIFF formatted");
|
||||
}
|
||||
else
|
||||
dbgSerial.println("SPIFFS Mounted .. ");
|
||||
writeFile(SPIFFS, "/www/index.htm", EQ2HBX_Version.c_str());
|
||||
listDir(SPIFFS, "/", 0);
|
||||
|
||||
server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.htm");
|
||||
|
||||
// Catch-All Handlers
|
||||
// Any request that can not find a Handler that canHandle it
|
||||
// ends in the callbacks below.
|
||||
server.onNotFound(onRequest);
|
||||
server.onFileUpload(onUpload);
|
||||
server.onRequestBody(onBody);
|
||||
|
||||
server.begin();
|
||||
// Add service to MDNS-SD
|
||||
MDNS.addService("_http", "_tcp", 80);
|
||||
MDNS.addService("_osc", "_udp", localUdpPort);
|
||||
//browseService("http", "tcp");
|
||||
}
|
||||
|
||||
if (!UDPFlag) {
|
||||
// ESP_NOW mode (EQMODWiFi responds to MAC protocol)
|
||||
dbgSerial.println("ESP_NOW Mode");
|
||||
InitESPNow();
|
||||
dbgSerial.println("ESPNOW2SerialServer");
|
||||
dbgSerial.print("Mount soft mac: "); dbgSerial.println(WiFi.softAPmacAddress());
|
||||
dbgSerial.print("Mount hard mac: "); dbgSerial.println(WiFi.macAddress());
|
||||
// esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
|
||||
esp_now_register_recv_cb(recvCallBack);
|
||||
esp_now_register_send_cb(sendCallBack);
|
||||
}
|
||||
else {
|
||||
dbgSerial.println("UDP Mode");
|
||||
udp.begin(localUdpPort);
|
||||
dbgSerial.println("UDP2SerialServer");
|
||||
if (APFlag)
|
||||
dbgSerial.printf("AP : ");
|
||||
else
|
||||
dbgSerial.printf("STA: ");
|
||||
dbgSerial.printf("Now listening at IP %s, UDP port %d\n", WiFi.softAPIP().toString().c_str(), localUdpPort);
|
||||
}
|
||||
|
||||
TxDIndex = 0;
|
||||
sendWiFi.len = 0;
|
||||
recvWiFi.len = 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
bool HBXCheckRx() {
|
||||
if (UDPFlag) {
|
||||
// UDP - SynScanPro UDP
|
||||
recvWiFi.len = udp.parsePacket();
|
||||
if (recvWiFi.len > 0) {
|
||||
// receive incoming UDP packets
|
||||
recvWiFi.len = udp.read(recvWiFi.text, 250);
|
||||
if (recvWiFi.len > 0) {
|
||||
recvWiFi.text[recvWiFi.len] = 0; // Null terminate
|
||||
|
||||
// dbgSerial.print("RxUDP - len: ");
|
||||
// dbgSerial.print(recvWiFi.len);
|
||||
// dbgSerial.print(", data: ");
|
||||
// dbgSerial.println(recvWiFi.text);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (recvWiFi.len > 0) { // Send data to mount Input data buffer for processing
|
||||
putRxDataIntoMountInputBuffer();
|
||||
return true; // Data received from UDP or ESP_NOW callback
|
||||
}
|
||||
else
|
||||
return false; // No Data received
|
||||
}
|
||||
|
||||
void HBXCheckTx() {
|
||||
if (UDPFlag) {
|
||||
// Get data to send to SynScanPro via UDP into WiFi buffer
|
||||
getTxDataFromMountOutputBuffer();
|
||||
// send back a reply, to the IP address and port we got the packet from
|
||||
if (sendWiFi.len > 0) {
|
||||
|
||||
// dbgSerial.print("TxUDP - len: ");
|
||||
// dbgSerial.print(sendWiFi.len);
|
||||
// dbgSerial.print(", data: ");
|
||||
// dbgSerial.println(sendWiFi.text);
|
||||
|
||||
udp.beginPacket(udp.remoteIP(), udp.remotePort());
|
||||
memcpy(sendWiFi8, &sendWiFi.text, sendWiFi.len);
|
||||
udp.write(sendWiFi8, sendWiFi.len);
|
||||
udp.endPacket();
|
||||
}
|
||||
sendWiFi.len = 0;
|
||||
TxDIndex = 0;
|
||||
}
|
||||
else {
|
||||
// Get data to send to ESP_NOW - EQMOD/SynScanPro Serial WiFi
|
||||
if (Connected) {
|
||||
getTxDataFromMountOutputBuffer();
|
||||
if (sendWiFi.len > 0)
|
||||
sendData(&serial_peer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/********************************************************
|
||||
Hardware Definitions
|
||||
====================
|
||||
*********************************************************/
|
||||
#pragma once
|
||||
|
||||
#define mESP32
|
||||
|
||||
// Configuration for WiFi interface
|
||||
// ================================
|
||||
|
||||
// UDP allows communications with the Skywatcher SynScan app on Laptop, Tablet or phone
|
||||
// ESPNOW is alocal area wifi net .. TODO
|
||||
// AP provides a n access point in absence of Telscope wifi network
|
||||
// STA enables use of wifi credentials to log on to Telescope wifi network
|
||||
|
||||
#define SelectUDP // Either UDP or ESPNOW
|
||||
#undef SelectAP // Either AP or STA
|
||||
|
||||
// Serial port definitions for HBX interface
|
||||
// =========================================
|
||||
|
||||
#ifdef mESP32
|
||||
#define dbgSerial Serial
|
||||
#define EQGSerial Serial2
|
||||
|
||||
#ifdef BTSerial
|
||||
#define EQGBluetooth SerialBT
|
||||
#endif
|
||||
#endif
|
||||
// Pin definitions for ESP32-HBX interface
|
||||
// =======================================
|
||||
|
||||
#ifdef mESP32
|
||||
// 8Pin RJ
|
||||
// =======
|
||||
// Pin8 Gnd
|
||||
#define HDAAz 25 // Pin7 on HBX interface
|
||||
#define HCLAz 26 // Pin6 on HBX interface
|
||||
#define HDAAlt 14 // Pin5 on HBX interface
|
||||
#define HCLAlt 27 // Pin4 on HBX interface
|
||||
#define HDAAux 18 // Pin3 on HBX interface
|
||||
#define HCLAux 19 // Pin2 on HBX interface
|
||||
// Pin1 Vbat
|
||||
|
||||
// 4Pin RJ
|
||||
// =======
|
||||
// Pin1 Gnd
|
||||
#define HDAAux 18 // Pin2 on HBX interface
|
||||
#define HCLAux 19 // Pin3 on HBX interface
|
||||
// Pin4 Vbat
|
||||
|
||||
#define H2C_INPUTPU INPUT_PULLUP // Set pin data input mode
|
||||
#define H2C_INPUT INPUT // Set pin data input mode
|
||||
#define H2C_OUTPUT OUTPUT // Set pin data output
|
||||
|
||||
// Pin definitions for LED indicators
|
||||
// ==================================
|
||||
#define EQGLED 21
|
||||
#define ETXLED 22
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
This directory is intended for PIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
Ładowanie…
Reference in New Issue