Arduino compile tests for V1.8.16

Separate compile folders for Mega, ESP32 serial, and ESP32 WiFi.
PC Synscan will work with all, Synscan Mobile only with WiFi.
pull/5/head
ozarchie 2021-12-20 13:59:38 +10:00
rodzic 3f80e090f4
commit 5d39b48036
13 zmienionych plików z 4072 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,225 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
EQG2HBX program definitions
===========================
*********************************************************/
#ifndef EQG2HBX
#define EQG2HBX
String EQ2HBX_Version = "EQG2HBX V1.05";
#ifdef ESP32
#include "WiFi.h"
#include "AsyncUDP.h"
#include <ArduinoOTA.h>
bool ota_started;
#endif
// Time related libararies
#include <Ticker.h>
#ifndef ESP32
#include <TimeLib.h> //https://github.com/PaulStoffregen/Time
#include <TimeAlarms.h> //https://github.com/PaulStoffregen/TimeAlarms
#endif
// Pin definitions for LED indicators
// ==================================
#ifdef mESP32
#define SCOPELED 22
#define EQGLED 21
#endif
// Jumpers to run test
// ==============================
#ifdef ESP32
#define TESTHBX 13 // GPI35
#endif
/**************************************************************
* Common variables
**************************************************************/
Preferences preferences;
unsigned long DelayTimer; // 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 AlarmDebugPrint;
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
#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
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 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 Speed; // Move speed
long TargetSpeed; // Target Move speed
char SpeedState; // Slowdown/speedup state
long Position; // Current position
long Target; // Current target delta
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 = 240 * SIDEREALRATE
unsigned long SIDEREALRATE; // Constants
unsigned long SOLARRATE;
unsigned long LUNARRATE;
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;
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";
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 long PreviousTime; // Used in HBX Monitor, Testing
// Testing only
unsigned char TestCount;
unsigned long TestLoopTime;
#endif

Wyświetl plik

@ -0,0 +1,322 @@
#include <dummy.h>
/*
Name: EQG2HBXE32.ino
Created: 2018-09-01 10:07:17 AM
Author: JOHNWIN10PRO\John
*/
/********************************************************
Initialize HBX, translate EQG to HBX
====================================
*********************************************************/
#define mESP32
#define mTEST
#include "HBXFileSystem.h"
#include "HBXWiFiServer.h"
#include "EQGProtocol.h"
#include "ETXProtocol.h"
#include "HBXComms.h"
#include "EQG2HBX.h" // All the declared variables
// Function Prototypes
//
void UpdateETX(void);
void CheckETXState(void);
void TimerDelaymS(unsigned long );
void TimerDelayuS(unsigned int);
// Functions
//
/**************************************************************************************************
* Read / Update ETX - Timer Driven
**************************************************************************************************/
void UpdateETX(void) {
}
/**********************************************
Multiple 1mS delay
***********************************************/
void TimerDelaymS(unsigned long d) {
delay(d);
}
/**********************************************
Multiple 1uS delay
***********************************************/
void TimerDelayuS(unsigned int d) {
delayMicroseconds(d);
}
void CheckETXStatus(unsigned char Motor) {
/**************************************************************************************************
* Get ETXStatus
**************************************************************************************************/
HBXGetStatus(Motor);
}
void CheckETXState(unsigned char Motor) {
/**************************************************************************************************
* Check ETXState
**************************************************************************************************/
ETXState(Motor); // Check the motor state
}
void HandleOTA()
{
StartOTAIfRequired();
ArduinoOTA.handle();
}
void StartOTAIfRequired()
{
if (ota_started)
return;
// Port defaults to 8266
// ArduinoOTA.setPort(8266);
// Hostname defaults to esp8266-[ChipID]
//if (ArduinoOTA.getHostname() && ArduinoOTA.getHostname().length())
// No authentication by default
ArduinoOTA.setPassword((const char *)"EQG2HBX");
ArduinoOTA.onStart([]() {
Serial.println("OTA Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nOTA End");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r\n", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
ota_started = true;
delay(500);
}
// =======================================================================================================
void setup()
{
#ifdef mESP32
dbgSerial.begin(115200); // debug
EQGSerial.begin(9600, SERIAL_8N1, 18, 19); // EQG via serial or WiFi
delay(10);
StartOTAIfRequired();
#endif
dbgSerial.println(EQ2HBX_Version);
DelayTimer = micros(); // Initialize timers, counts
StatusTimer = DelayTimer;
StatusTime = DelayTimer;
EQGErrorValue = 0;
#ifdef mESP32
HBXWiFiSetup();
#endif
pinMode(SCOPELED, OUTPUT);
pinMode(EQGLED, OUTPUT);
digitalWrite(SCOPELED, LOW);
digitalWrite(EQGLED, LOW);
pinMode(TESTHBX, INPUT_PULLUP); // Initialize Mode jumpers
digitalWrite(TESTHBX, HIGH); // Use internal PUR, write 1 to O/P
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
// **************************
// Check for HBX Testing Mode
// ==========================
dbgSerial.print("digitalRead(TESTHBX) : ");
dbgSerial.println(digitalRead(TESTHBX));
while (digitalRead(TESTHBX) == 0) { // Check if test jumper installed
dbgSerial.print("digitalRead(TESTHBX) : ");
dbgSerial.println(digitalRead(TESTHBX));
HBXTestLoop(); // Execute test code until jumper removed
};
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.print(station);
dbgSerial.print(", ");
preferences.end();
AzInitialise(telescope);
AltInitialise(telescope);
PrintRatioValues(telescope);
PrintHbxValues(AzMotor);
PrintHbxValues(AltMotor);
// Initialize HBX communications as outputs
// It will use H2X communications
HCL1Talk(); // Set for Talking on RAClk
HCL2Talk(); // Set for Talking on DECClk
HDAListen();
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
**************************************************************************************************/
HandleOTA();
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);
}
if ((micros() - StatusTimer) > (STATUSDELAY * 1000)) { // ~50mS
if (StatusSelect) StatusSelect = false;
else StatusSelect = true;
StatusTimer = micros();
if (StatusSelect) CheckETXStatus(AzMotor);
else 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();
}
// End loop()

Wyświetl plik

@ -0,0 +1,218 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG Protocol function definitions
=================================
*********************************************************/
#include <Arduino.h>
#ifndef EQGProtocol
#define EQGProtocol
#define CR 0x0d
#define LF 0x0a
float SIDEREALSECS = 86164.098903691; // Some astronomical constants
float SOLARSECS = 86400;
float LUNARSECS = 89309;
#define EQG_CMNDSTART 0x01
#define EQG_WAITFORCR 0x77
#define EQG_INTERPRET 0x78
/*
// Get Motor Controller Version
// :e1[0D]
// =llhhMM[0D]
// ===========
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
*/
// :qm
// 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
/*
// 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;
*/
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
// E
// F
// EQ6 returns !0
// ABCDEF
// AZEQ5 =0B6000 at boot
// AZEQ6 =0B3000
// EQ8 =076000
// EFCDAB
#define AEQ6 0x003000 // !:J3, Polar LED
#define AEQ5 0x003008 // !:J3, Polar LED, az/eq
#define AEQ3 0x003000 // !:J3, Polar LED
#define AAZEQ5 0x00B008 // !:J3, Polar LED, WiFi, AZ/EQ
// Motor firmware versions
#define VEQ6 0x000204 // Pretend EQ6/5
#define VHEQ5 0x010204 // Pretend HEQ5
#define VEQ5 0x020204 // Pretend EQ5
#define VEQ3 0x030301 // Pretend EQ3
#define VEQ8 0x040301 // Pretend EQ3
#define VAZEQ6 0x050211 // Pretend AZEQ6
#define VAZEQ5 0x060301 // Pretend AZEQ5
#define EQGVERSION VEQ6
#define EQGASSETS AEQ6
// :I := ( :b * 1296000 / :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 / 1,296,000
// Speed = g*(b*129600/a)/I
// ==============================
// IVALUE = (axis[EQGMOTOR].bVALUE * 1296000) / axis[EQGMOTOR].STEPSPER360)
#define EQG_gVALUE 0x000010
#define EQGMAXIMUMSPEED 12 // 0x0C
// EQG 'G' Command - SET move parameters
#define DIRECTION 0x00000001 // Increasing(0) Decreasing(1)
#define HEMISPHERE 0x00000002 // North(0) South(1)
// EQG 'f' Command - GET Motor status bit definitions
// 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 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: nibble 1
#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)
void EQGState(void);
void EQGError(unsigned char);
void EQGAction(void);
void TimerDelaymS(unsigned long);
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 puthexn(unsigned char);
void puthexb(unsigned char);
void puthexw(unsigned int);
void puthexl(unsigned long);
void putdecn(unsigned char);
void putdecb(unsigned char);
void putdecw(unsigned int);
void putdecl(unsigned long);
#endif

Wyświetl plik

@ -0,0 +1,968 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
#include <stdio.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 * 1296000 / :a ) / Speed ( where Speed is in arcsec/sec )
Speed = g*(b*1296000/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 / 1296000
*/
/********************************************************
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) {
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: nibble 1
// 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
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
// 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;
}
// 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
// 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
// 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
// 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
// dbgSerial.print("HIGH SPEED SLEW");
break;
}
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
// long Speed;
// From EQMOD
// Multiplier = EQGSidereal / :I
// MultiplierHi = EQGSidereal*g / :I
// For ETX
// Speed = ETXSidereal * Multiplier
// SpeedHi = ETXSidereal * MultiplierHi
// Calculation
// Speed = SiderealRate * (:ISidereal / )
// SpeedHi = SiderealRate * ((Sidereal*g) / :I)
axis[EQGMOTOR].TargetSpeed = EQGP1; // Set the target 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].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].Speed, 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].Speed, 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;
}

Wyświetl plik

@ -0,0 +1,91 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
EQG Protocol function definitions
=================================
*********************************************************/
#ifndef ETXProtocol
#define ETXProtocol
#define MotorAz 0x01 // Pin3 on HBX interface
#define MotorAlt 0x02 // Pin5 on HBX interface
#define AzMotor MotorAz
#define 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
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
const float ArcSecs360 = 1296000; // Arcsecs / 360
#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
#define H2X_INPUTPU INPUT_PULLUP // Set pin data input mode
#define H2X_INPUT INPUT // Set pin data input mode
#define H2X_OUTPUT OUTPUT // Set pin data output
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);
#endif

Wyświetl plik

@ -0,0 +1,635 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
ETX Protocol related functions
==============================
*********************************************************/
bool ETXState(unsigned char Motor) {
long distance;
// int s1;
switch(axis[Motor].ETXMotorState) {
case ETXIdle:
break;
case ETXCheckStartup:
if (axis[Motor].ETXMotorStatus & MOVEAXIS) { // Start moving
//dbgSerial.println(""); dbgSerial.print("ETXCheckStartup - Motor: "); dbgSerial.print(Motor); dbgSerial.print(" MOVE");
distance = axis[Motor].Target - axis[Motor].Position; // Distance to target
if (axis[Motor].ETXMotorStatus & MOVEDECR) // If it is decreasing
distance = TwosComplement(distance);
//dbgSerial.print(" Distance: "); dbgSerial.print(distance);
if (axis[Motor].ETXMotorStatus & MOVEHIGH) { // High Speed Slew ?
if (axis[Motor].ETXMotorStatus & MOVESLEW) {
axis[Motor].ETXMotorState = ETXSlewMotor; // Move axis using high speed multiplier
//dbgSerial.print(" HIGH SLEW");
}
}
else { // GoTo or Low Speed Slew
axis[Motor].ETXMotorState = ETXCheckSpeed;
//dbgSerial.print(" GOTO");
}
if (axis[Motor].MotorControl & GoToHBX) { // Check GoTo?
if (axis[Motor].MotorControl & SlewHBX) { // May need to slew for large changes
axis[Motor].ETXMotorState = ETXSlewMotor; // Slew to M-point
//dbgSerial.print(" SLEW");
}
else {
axis[Motor].ETXMotorState = ETXCheckSpeed;
axis[Motor].TargetSpeed = axis[Motor].DEGREERATE1; // Set initial speed for 'HIGH SPEED GOTO'
if (distance < axis[Motor].OneDegree)
axis[Motor].TargetSpeed = (axis[Motor].TargetSpeed >> 1);
if (distance < (axis[Motor].OneDegree >> 2))
axis[Motor].TargetSpeed = (axis[Motor].TargetSpeed >> 1);
axis[Motor].Speed = 0; // Starting from 0
//dbgSerial.print(" STEP");
}
if (distance < OffsetMax) { // Check for really small moves (< 16 steps)
axis[Motor].ETXMotorState = ETXMotorEnd; // Use Adjust offset
//dbgSerial.print(" OFFSET");
}
if (distance > (axis[Motor].OneDegree << 3)) { // Always slew for > 8 degrees
axis[Motor].ETXMotorState = ETXSlewMotor;
//dbgSerial.print(" GoToSLEW");
}
}
}
break;
case ETXSlewMotor:
//dbgSerial.println(""); dbgSerial.print("ETXSlewMotor Motor: "); dbgSerial.print(Motor); dbgSerial.print(" SLEW Cmd: ");
digitalWrite(SCOPELED, HIGH); // Turn on the 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;
//dbgSerial.print(axis[Motor].Command, HEX);
// Send the command to the ETX
HBXSendCommand(axis[Motor].Command, Motor); // SLEW
axis[Motor].EQGMotorStatus |= MOVEAXIS; // Tell EQx
axis[Motor].Speed = axis[Motor].DEGREERATE1; // Set "current speed" for later speed checks
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].Speed = axis[Motor].DEGREERATE1;
axis[Motor].SpeedState = 0;
//dbgSerial.print(" GoToSLEW END");
}
}
if (axis[Motor].MotorControl & SlewHBX) { // Slewing to M-point
axis[Motor].Speed = axis[Motor].DEGREERATE1; // Indicate current speed (approx)
axis[Motor].ETXMotorState = ETXCheckSlowDown; // Slew until SlowDown
}
/*
dbgSerial.println(""); dbgSerial.print("ETXSlewMotor Motor: "); dbgSerial.print(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(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
dbgSerial.print(" Speed: "); dbgSerial.print(axis[Motor].Speed, HEX);
dbgSerial.print(" TargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
dbgSerial.print(" SpeedState: "); dbgSerial.println(axis[Motor].SpeedState, HEX);
*/
break;
case ETXStepMotor:
//dbgSerial.println(""); dbgSerial.print("ETXStepMotor Motor: "); dbgSerial.print(Motor); dbgSerial.print(" STEP Cmd: ");
digitalWrite(SCOPELED, HIGH); // Turn on the LED
if (axis[Motor].MotorControl & SpeedHBX) // Stepping, High or Low speed
axis[Motor].Command = SpeedStart; // Use SpeedStart to start motion
else {
axis[Motor].Command = SpeedChnge; // Use SpeedChnge once started
}
axis[Motor].MotorControl &= ~SpeedHBX; // Clear flag
// Set the speed, and direction
// ----------------------------
P1 = axis[Motor].Speed;
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;
//dbgSerial.print(axis[Motor].Command, HEX);
// Send the command
// ----------------
if (HBXSendCommand(axis[Motor].Command, Motor)) // Command OK?
HBXSend3Bytes(Motor); // Send the speed
axis[Motor].EQGMotorStatus |= MOVEAXIS; // Tell EQx
axis[Motor].ETXMotorState = ETXCheckSpeed; // 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].Speed == axis[Motor].TargetSpeed)
axis[Motor].ETXMotorState = ETXCheckPosition;
}
else if (axis[Motor].Speed == 0) { // Stop issued
axis[Motor].ETXMotorState = ETXStopMotor;
}
else if (axis[Motor].Speed == axis[Motor].TargetSpeed) { // Else slewing at speed
axis[Motor].ETXMotorState = ETXIdle;
}
break;
case ETXCheckSlowDown:
// Check if Slowdown reached
// Calculate absolute distance to slowdown
// ---------------------------------------
/*
dbgSerial.println(""); dbgSerial.print("ETXCheckSlowDown Motor: "); dbgSerial.print(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(", SD: "); dbgSerial.print(axis[Motor].SlowDown, HEX);
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
dbgSerial.print(" Speed: "); dbgSerial.print(axis[Motor].Speed, HEX);
dbgSerial.print(" TargetSpeed: "); 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:
// Speeding Up
// ===========
/*
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(Motor);
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
dbgSerial.print(" iSpeed: "); dbgSerial.print(axis[Motor].Speed, HEX);
dbgSerial.print(" iTargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
*/
axis[Motor].ETXMotorState = ETXStepMotor; // Preset set speed as next action
// Ramp up to speed
if ((axis[Motor].TargetSpeed != 0) && (axis[Motor].TargetSpeed > axis[Motor].Speed)) {
if ((axis[Motor].TargetSpeed - axis[Motor].Speed) > (axis[Motor].SIDEREALRATE << 6)) { // 64x sidereal
axis[Motor].Speed += ((axis[Motor].TargetSpeed - axis[Motor].Speed) >> 1); // Ramp up approx .5 difference
// while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
}
else {
axis[Motor].Speed = axis[Motor].TargetSpeed;
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command
}
}
// Ramp down to speed
else if ((axis[Motor].TargetSpeed != 0) && (axis[Motor].Speed > axis[Motor].TargetSpeed)) {
axis[Motor].Speed -= ((axis[Motor].Speed - axis[Motor].TargetSpeed) >> 2); // Approx .75
if ((axis[Motor].Speed - axis[Motor].TargetSpeed) <= (axis[Motor].SIDEREALRATE << 7)) {
axis[Motor].Speed = 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
}
}
// Ramp down to stop
else if ((axis[Motor].TargetSpeed == 0) && (axis[Motor].Speed != 0)) {
if (axis[Motor].ETXMotorStatus & MOVESLEW) {
axis[Motor].ETXMotorState = ETXStopMotor;
}
else if (axis[Motor].Speed >= (axis[Motor].SIDEREALRATE << 7)) { // Ramp down to 128x sidereal
axis[Motor].Speed -= (axis[Motor].Speed >> 2); // Approximately .75
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor command
axis[Motor].MotorControl |= SpeedHBX; // Use 0x01 command
}
else
axis[Motor].ETXMotorState = ETXStopMotor; // OK, Stop the motor
}
// Switch to position check, when we are at speed - check done in ETXStepMotor
//dbgSerial.print(" oSpeed: "); dbgSerial.print(axis[Motor].Speed, HEX);
//dbgSerial.print(" oTargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
break;
case ETXCheckPosition:
// Check if Target acquired
// ------------------------
// Calculate absolute distance to target
// -------------------------------------
/*
dbgSerial.println(""); dbgSerial.print("ETXCheckPosition Motor: "); dbgSerial.print(Motor);
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
dbgSerial.print(" Speed: "); dbgSerial.print(axis[Motor].Speed, HEX);
dbgSerial.print(" TargetSpeed: "); dbgSerial.print(axis[Motor].TargetSpeed, HEX);
dbgSerial.print(" SpeedState: "); dbgSerial.print(axis[Motor].SpeedState, HEX);
*/
if (!(axis[Motor].MotorControl & GoToHBX)) { // Slewing so update position
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 <= 0x100) && (axis[Motor].SpeedState == 2)) {
axis[Motor].TargetSpeed = axis[Motor].Speed >> 2; // 1/16
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
axis[Motor].SpeedState += 1;
}
else if ((distance <= 0x200) && (axis[Motor].SpeedState == 1)) {
axis[Motor].TargetSpeed = axis[Motor].Speed >> 1; // 1/4
axis[Motor].MotorControl &= ~SpeedHBX; // Use 0x00 command
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
axis[Motor].SpeedState += 1;
}
else if ((distance <= 0x400) && (axis[Motor].SpeedState == 0)) {
axis[Motor].TargetSpeed = axis[Motor].Speed >> 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:
//dbgSerial.println(""); dbgSerial.print("ETXStopMotor Motor: "); dbgSerial.print(Motor);
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].ETXMotorState = ETXCheckStartup;
axis[Motor].TargetSpeed = axis[Motor].Speed; // For any subsequent move
axis[Motor].Speed = 0;
break;
case ETXMotorEnd:
/*
dbgSerial.println(""); dbgSerial.print("ETXMotorEnd Motor: "); dbgSerial.print(Motor);
dbgSerial.print(" <sts: "); dbgSerial.print(axis[Motor].ETXMotorStatus, HEX); dbgSerial.print("> ");
dbgSerial.print(", Pos: "); dbgSerial.print(axis[Motor].Position, HEX);
dbgSerial.print(", Inc: "); dbgSerial.print(axis[Motor].Increment, HEX);
dbgSerial.print("->Tgt: "); dbgSerial.print(axis[Motor].Target, HEX);
*/
digitalWrite(SCOPELED, LOW); // Turn off the 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(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.println(""); dbgSerial.print("Motor: "); dbgSerial.print(Motor); dbgSerial.print(", Posn: "); dbgSerial.print(axis[Motor].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 values
axis[AzMotor].aVALUE = axis[AzMotor].Vanes * (float)4 * axis[AzMotor].GbxRatio * axis[AzMotor].XferRatio * axis[AzMotor].WormTeeth;
axis[AzMotor].MeadeRatio = axis[AzMotor].aVALUE / ArcSecs360; // Distance for one arcsec
axis[AzMotor].bVALUE = (MeadeSidereal * axis[AzMotor].MeadeRatio * axis[AzMotor].aVALUE * SiderealArcSecs) / ArcSecs360;
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].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 values
axis[AltMotor].aVALUE = axis[AltMotor].Vanes * (float)4 * axis[AltMotor].GbxRatio * axis[AltMotor].XferRatio * axis[AltMotor].WormTeeth;
axis[AltMotor].MeadeRatio = axis[AltMotor].aVALUE / ArcSecs360; // Distance for one arcsec
axis[AltMotor].bVALUE = MeadeSidereal * axis[AltMotor].MeadeRatio * axis[AltMotor].aVALUE * SiderealArcSecs / ArcSecs360;
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;
// ETX
axis[AltMotor].HBXP1 = 0x00;
axis[AltMotor].HBXP2 = 0x00;
axis[AltMotor].HBXP3 = 0x00;
axis[AltMotor].HBXP4 = 0x00;
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].EQGMotorStatus = MOVESLEW;
axis[AltMotor].ETXMotorState = ETXCheckStartup;
}
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("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;
float r;
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);
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);
}
}

Wyświetl plik

@ -0,0 +1,85 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
EQG Protocol function definitions
=================================
*********************************************************/
#ifndef HBXComms
#define HBXComms
#include <EEPROM.h>
// Serial port definitions for HBX interface
// =========================================
#ifdef mESP32
#define dbgSerial Serial
#define EQGSerial Serial2
#endif
// Pin definitions for HBX interface
// =================================
#ifdef mESP32
#define HDA1 27 // Pin2 on HBX interface
#define HCL1 26 // Pin3 on HBX interface
#define HDA2 14 // Pin4 on HBX interface
#define HCL2 25 // Pin5 on HBX interface
#define HDAX 14 // Pin6 on HBX interface
#define HCLX 25 // Pin7 on HBX interface
#endif
#define CR 0x0d
#define LF 0x0a
#define HBXLEN 16
#define HBXMASK HBXLEN-1
#define H2XRESETTIME 25 // Reset H2X bus
#define BITTIME 96 // 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
#define CLOCKTIMEOUT 50 // H2X Clock transition timeout (uS) (for monitor mode)
#define MOTORDETECT 500 // H2X Detect Motor controller
unsigned char HBXBitTime = BITTIME;
void TimerDelayuS(unsigned int);
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(void);
void HDATalk(void);
void HCL1Listen(void);
void HCL1Talk(void);
void HCL2Listen(void);
void HCL2Talk(void);
void HBXReset(void);
//bool ResetMotor(unsigned char);
long TwosComplement(long);
//unsigned long eeprom_crc(void);
//unsigned long get_eeprom_crc(void);
//bool set_eeprom_crc(void);
//bool check_eeprom_crc(void);
// Testing
void HBXTestLoop(void);
void HBXTest(void);
bool HBXGet2Status(void);
#endif

Wyświetl plik

@ -0,0 +1,294 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
HBX Comms related functions
===========================
*********************************************************/
// HBX Attempt to reset
// --------------------
void HBXMotorReset(unsigned char Motor)
{
/*
// Write LOW
HDATalk();
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();
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 Low, High for reset, time ~.75s
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelaymS(MOTORDETECT);
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelaymS(MOTORDETECT >> 1);
}
// HBX transmission functions
// ==========================
// HBX Send a command
// ------------------
bool HBXSendCommand(unsigned char Command, unsigned char Motor) {
if (Command != GetStatus){
dbgSerial.println(""); dbgSerial.print("+++ "); dbgSerial.print(Motor);
}
axis[Motor].Command = Command;
// Send the start sequence
// -----------------------
if (HBXStartSequence(Motor)) {
// Send the command byte
// ---------------------
HBXSendByte(Command, Motor);
return(true);
}
else {
return(false);
}
}
// HBX Initiate start sequence
// ---------------------------
bool HBXStartSequence(unsigned char Motor) {
// 1. HDA as input
HDAListen();
// 2. Set clock low
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(HBXBitTime >> 1); // 1/2 bit-time
// 3. Wait for data low (HDA1 = 0) by MC, or timeout
H2XStart = micros();
do {
H2XTimer = micros() - H2XStart;
} while ((digitalRead(HDA1) == 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(HDA1) == 1) || (H2XTimer >= (HBXBitTime << 3))) {
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH); // Set clock high, and
return(false); // error exit if no response from Motor
}
// 5. Set clock high if data low occurred (i.e. MC acknowledged clock low)
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(HBXBitTime >> 1);
// 6. Wait for data line release (HDA1 = 1) by MC, or timeout
H2XStart = micros();
do {
H2XTimer = micros() - H2XStart;
} while ((digitalRead(HDA1) == 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 (axis[Motor].Command != GetStatus) {
dbgSerial.print("-> "); dbgSerial.print(databyte, HEX);
}
HDATalk(); // 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(HDA1, HIGH);
else digitalWrite(HDA1, LOW);
TimerDelayuS(HBXBitTime >> 1); // Let data stabilise
mask = mask >> 1; // Next data bit
// Set clock low
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(HBXBitTime);
// Set clock high
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, 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();
TimerDelayuS(HBXBitTime);
}
// HBX Send two bytes in sequence
// ------------------------------
void HBXSend2Bytes(unsigned char Motor) {
HBXSendByte(axis[Motor].HBXP1, Motor);
HBXSendByte(axis[Motor].HBXP2, Motor);
}
// 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);
}
// HBX Get a single byte
// ----------------------
unsigned char HBXGetByte(unsigned char Motor) {
// HDA as input
HDAListen();
axis[Motor].HBXBitCount = 8;
axis[Motor].HBXData = 0;
// Clock was set high before entry
while (axis[Motor].HBXBitCount) {
// Set clock low
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(HBXBitTime >> 1);
// Read data bit
axis[Motor].HBXData = axis[Motor].HBXData << 1; // Shift previous bit
if (digitalRead(HDA1)) axis[Motor].HBXData |= 0x01; // Read next bit
axis[Motor].HBXBitCount--; // Need eight bits
TimerDelayuS(HBXBitTime-(HBXBitTime >> 1)); // Wait for low time
// Set clock high
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, 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
// ------------------------
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(HBXBitTime >> 1);
axis[Motor].HBXP4 |= digitalRead(HDA1); // Read the battery error bit
TimerDelayuS(HBXBitTime-(HBXBitTime >> 1));
if (Motor == MotorAz)digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(HBXBitTime);
if (axis[Motor].Command != GetStatus) {
dbgSerial.print("- "); dbgSerial.print(axis[Motor].HBXP4, HEX);
}
axis[Motor].HBXCount = 4;
}
// H2X Low level Functions
// -----------------------
void HDAListen() {
digitalWrite(HDA1, HIGH);
pinMode(HDA1, H2X_INPUTPU);
}
void HDAFloat() {
pinMode(HDA1, H2X_INPUT);
}
void HDATalk() {
digitalWrite(HDA1, HIGH);
pinMode(HDA1, H2X_OUTPUT);
}
void HCL1Listen() {
pinMode(HCL1, H2X_INPUT);
}
void HCL1Talk() {
digitalWrite(HCL1, HIGH);
pinMode(HCL1, H2X_OUTPUT);
}
void HCL2Listen() {
pinMode(HCL2, H2X_INPUT);
}
void HCL2Talk() {
digitalWrite(HCL2, HIGH);
pinMode(HCL2, H2X_OUTPUT);
}
void HBXReset() {
int ClockCount = 0;
// Set clocks high
HCL1Talk();
HCL2Talk();
digitalWrite(HCL1, HIGH);
digitalWrite(HCL2, HIGH);
// Set data inbound
HDAListen();
TimerDelayuS(HBXBitTime);
// Data should be high
while ((!digitalRead(HDA1)) && (ClockCount < 25)) {
digitalWrite(HCL1, LOW);
digitalWrite(HCL2, LOW);
TimerDelayuS(HBXBitTime);
digitalWrite(HCL1, HIGH);
digitalWrite(HCL2, HIGH);
TimerDelayuS(HBXBitTime);
ClockCount += 1;
}
}
long TwosComplement(long p) { // Calculate 2s complement
long q;
q = ~p; // Bitwise invert
q = q + 1; // +1
return q;
}

Wyświetl plik

@ -0,0 +1,12 @@
#pragma once
/**************************************************************
* SPIFFS filesystem
* Only invoked in STA mode
*/
#include <FS.h>
#include <SPIFFS.h>
#include <SPIFFSEditor.h>
#include <Preferences.h>
#define FORMAT_SPIFFS_IF_FAILED true

Wyświetl plik

@ -0,0 +1,101 @@
/* SPIFFS functions
*/
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");
}
}

Wyświetl plik

@ -0,0 +1,118 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG Serial WiFi
===============
*********************************************************/
#ifndef HBXWiFiServer
#define HBXWiFiServer
#include <Arduino.h>
#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 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);
#endif // HBXWiFiServer

Wyświetl plik

@ -0,0 +1,484 @@
// HBXSerialServer.ino
// https://esp-idf.readthedocs.io/en/latest/api-reference/wifi/esp_now.html
// 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) {
dbgSerial.write(EQGTxBuffer[EQGTxoPtr]);
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", "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
UDPFlag = true; // Either UDP or ESPNOW
APFlag = true; // Either AP or STA
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", "EQMODWiFi"); // Default EQMOD
if (preferences.getString("AP_PASS", "none") == "none")
preferences.putString("AP_PASS", "CShillit0");
ssid = preferences.getString("AP_SSID", "none");
pass = preferences.getString("AP_PASS", "none");
preferences.end();
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ip, ip, netmask); // softAP ip
WiFi.softAP(ssid.c_str(), pass.c_str()); // softAP ssid, pass
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
if (preferences.getString("STA_SSID", "none") == "none")
preferences.putString("STA_SSID", "HAPInet"); // Default Home Network
if (preferences.getString("STA_PASS", "none") == "none")
preferences.putString("STA_PASS", "HAPIconnect");
ssid = preferences.getString("STA_SSID", "none");
pass = preferences.getString("STA_PASS", "none");
preferences.end();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), pass.c_str());
int i = 0;
while ((WiFi.status() != WL_CONNECTED) && (i++ < 50)) {
delay(100);
dbgSerial.print(i); dbgSerial.print(", ssid: "); dbgSerial.print(ssid.c_str()); dbgSerial.print(", pass: "); dbgSerial.println(pass.c_str());
}
if (i >= 50) {
WiFi.begin("HAPInet", "HAPIconnect");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
dbgSerial.print("!");
}
}
dbgSerial.println(" connected");
if (!MDNS.begin("eqmodwifi")) {
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
// Load 'server.on' responses
AsyncServerResponseSetup();
WiFi.scanNetworks();
// 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");
}
dbgSerial.print("ssid: "); dbgSerial.println(ssid.c_str());
dbgSerial.print("pass: "); dbgSerial.println(pass.c_str());
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("Now listening at IP %s, UDP port %d\n", WiFi.softAPIP().toString().c_str(), localUdpPort);
else
dbgSerial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().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);
}
}
}

Wyświetl plik

@ -0,0 +1,519 @@
/*
* Copyright 2017, 2018 John Archbold
*/
#include <Arduino.h>
/********************************************************
Test HBX communications
=======================
*********************************************************/
void HBXTestLoop(void) {
TestCount = 0;
//while (digitalRead(TESTHBX) == 0) {
while (1) {
dbgSerial.println("Test HBX commands to ETX");
HBXTest();
TestCount += 1;
TestLoopTime = millis();
// Read motor status until jumper removed
while((millis() - TestLoopTime) < 1000) { // 5s between tests
// HBXGet2Status();
}
}
}
void HBXTest(void)
{
// Initialize HBX communications as outputs
// It will use I2C-like communications
dbgSerial.println("**********************************************");
dbgSerial.print("Test Number - ");
dbgSerial.println(TestCount);
dbgSerial.println("**********************************************");
HCL1Talk(); // Set for Talking on RAClk
HCL2Talk(); // Set for Talking on DECClk
HDAListen();
TimerDelaymS(STARTTIME);
axis[AzMotor].PrintStatus0 = 1; // Enable print of status = no change
axis[AltMotor].PrintStatus0 = 1; // Enable print of status = no change
//if (TestCount == 0) {
dbgSerial.println("Test - HBX Initialization");
axis[AzMotor].Position = ETX_CENTRE;
axis[AzMotor].Target = axis[AzMotor].Position;
axis[AzMotor].DirnSpeed = 0x000;
axis[AzMotor].Speed = 0x000000;
axis[AzMotor].ETXMotorStatus = MOVESLEW;
axis[AltMotor].Position = ETX_CENTRE;
axis[AltMotor].Target = axis[AltMotor].Position;
axis[AltMotor].DirnSpeed = 0x000;
axis[AltMotor].Speed = 0x000000;
axis[AltMotor].ETXMotorStatus = MOVESLEW;
// Reset the motors (RA and DEC)
dbgSerial.println("Test - Wait for motors");
// 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)
do {
P1 = 0;
if (HBXSendCommand(GetLEDI, AzMotor))
P2 = HBXGetByte(AzMotor);
if ((P2 != 0) && (P2 != 0xFF)) P1 += 1;
TimerDelaymS(CMNDTIME);
if (HBXSendCommand(GetLEDI, AltMotor))
P2 = HBXGetByte(AltMotor);
if ((P2 != 0) && (P2 != 0xFF)) P1 += 1;
TimerDelaymS(CMNDTIME);
} while (P1 < 2);
// Stop the motors (Az and Alt)
dbgSerial.println("Test - Stop motors");
HBXStop2Motors();
// Read status
dbgSerial.println("");
dbgSerial.println("1 Test - Read Status");
HBXGet2Status(); // Check and read both motor states
dbgSerial.println("Test - Get Motor Type and set ETX Encoder LED currents");
axis[AzMotor].MotorType = 0x00;
while (!axis[AzMotor].MotorType) {
if (HBXSendCommand(GetMotorType, AzMotor))
axis[AzMotor].MotorType = HBXGetByte(AzMotor);
HBXPrintStatus(AzMotor);
}
preferences.begin("EQG2HBX", false); // Access EQG2HBX namespace
// Handle position sensors LED current
// -----------------------------------
if (preferences.getUChar("AzLEDI", 0) == 0) { // If it does not exist, return 0
// Calibrate motors
if (HBXSendCommand(CalibrateLED, AzMotor)) TimerDelaymS(2500);
if (HBXSendCommand(CalibrateLED, AltMotor)) TimerDelaymS(2500);
// Read the calibration
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.println(axis[AltMotor].HBXLEDI);
// Save it to preferences
preferences.putUChar("AzLEDI", axis[AzMotor].HBXLEDI);
preferences.putUChar("AltLEDI", axis[AltMotor].HBXLEDI);
}
// Read stored LED currents
axis[AzMotor].HBXLEDI = preferences.getUChar("AzLEDI", 0);
axis[AltMotor].HBXLEDI = preferences.getUChar("AltLEDI", 0);
preferences.end();
// Set the MC 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 to Zero
axis[AzMotor].HBXP1 = 0x00;
axis[AzMotor].HBXP2 = 0x00;
axis[AzMotor].HBXP3 = 0x00;
axis[AltMotor].HBXP1 = 0x00;
axis[AltMotor].HBXP2 = 0x00;
axis[AltMotor].HBXP3 = 0x00;
// Set the Offset Clear Command
dbgSerial.println("Test - Reset any ETX offset bytes");
if (HBXSendCommand(SetOffset, AzMotor))
HBXSend2Bytes(AzMotor);
HBXPrintStatus(AzMotor);
TimerDelaymS(CMNDTIME);
if (HBXSendCommand(SetOffset, AltMotor))
HBXSend2Bytes(AltMotor);
HBXPrintStatus(AltMotor);
TimerDelaymS(CMNDTIME);
//}
/*
dbgSerial.println("Test - Stop motors");
HBXStop2Motors();
// First Read, clear counters
dbgSerial.println("Test - Read Both Motor States");
HBXGet2Status();
dbgSerial.println("Test - Begin motor move tests");
//}
// Test different motor speeds
dbgSerial.println("Test - Motor Speed Tests");
dbgSerial.println("========================");
dbgSerial.println("Test - SIDEREAL");
axis[AzMotor].ETXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].ETXMotorStatus |= MOVEDIRN;
axis[AzMotor].Speed = AzSIDEREALRATE; // Sidereal
axis[AltMotor].Speed = AltSIDEREALRATE;
HBXPrintPosn(5, 1000); // Show location each second
dbgSerial.println("Test - SIDEREAL - Stop motors");
HBXStop2Motors();
dbgSerial.println("Test - OneDegree/sec forward");
axis[AzMotor].ETXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].ETXMotorStatus |= MOVEDIRN;
axis[AzMotor].Speed = AzDEGREERATE1; // One degree/sec
axis[AltMotor].Speed = AltDEGREERATE1; // One degree/sec
HBXPrintPosn(5, 500); // Show location each tenth of a second
dbgSerial.println("Test - OneDegree/sec forward - Stop motors");
HBXStop2Motors();
dbgSerial.println("Test - OneDegree/sec reverse");
axis[AzMotor].ETXMotorStatus &= ~MOVEDIRN; // Reverse
axis[AltMotor].ETXMotorStatus &= ~MOVEDIRN;
axis[AzMotor].Speed = AzDEGREERATE1; // One degree/sec
axis[AltMotor].Speed = AltDEGREERATE1; // One degree/sec
HBXPrintPosn(5, 500); // Show location each each tenth of a second
dbgSerial.println("Test - OneDegree/sec reverse - Stop motors");
HBXStop2Motors();
dbgSerial.println("Test - TwoDegrees/sec forward");
axis[AzMotor].ETXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].ETXMotorStatus |= MOVEDIRN;
axis[AzMotor].Speed = AzDEGREERATE1*2; // Two degrees/sec
axis[AltMotor].Speed = AltDEGREERATE1*2; // Two degrees/sec
HBXPrintPosn(5, 1000); // Show location each tenth of a second
dbgSerial.println("Test - TwoDegrees/sec forward - Stop motors");
HBXStop2Motors();
dbgSerial.println("Test - TwoDegrees/sec reverse");
axis[AzMotor].ETXMotorStatus &= ~MOVEDIRN; // Reverse
axis[AltMotor].ETXMotorStatus &= ~MOVEDIRN;
axis[AzMotor].Speed = AzDEGREERATE1*2; // Two degrees/sec
axis[AltMotor].Speed = AltDEGREERATE1*2; // Two degrees/sec
HBXPrintPosn(5, 1000); // Show location each each tenth of a second
dbgSerial.println("Test - TwoDegrees/sec reverse - Stop motors");
*/
HBXStop2Motors();
dbgSerial.println("");
dbgSerial.println("Test - 0x01 Command");
axis[AzMotor].MotorControl &= ~MOVEDECR; // Forward
axis[AltMotor].MotorControl &= ~MOVEDECR;
axis[AzMotor].MotorControl |= SpeedHBX; // High speed
axis[AltMotor].MotorControl |= SpeedHBX;
axis[AzMotor].Speed = axis[AzMotor].SIDEREALRATE; // Start at Sidereal
axis[AltMotor].Speed = axis[AltMotor].SIDEREALRATE;
do {
// HBXPrintSpeed(1, 10000); // Print location
axis[AzMotor].Speed += axis[AzMotor].SIDEREALRATE;
axis[AzMotor].ETXMotorState = ETXStepMotor;
ETXState(AzMotor);
TimerDelaymS(CMNDTIME);
// delay(2000);
// } while (axis[AzMotor].Speed < 0x600000);
// do {
// HBXPrintSpeed(1, 10000); // Print location
axis[AltMotor].Speed += axis[AltMotor].SIDEREALRATE;
axis[AltMotor].ETXMotorState = ETXStepMotor;
ETXState(AltMotor);
TimerDelaymS(CMNDTIME);
HBXGet2Status();
TimerDelaymS(CMNDTIME);
TimerDelaymS(2000);
} while (axis[AltMotor].Speed < (axis[AltMotor].SIDEREALRATE << 3));
dbgSerial.println("Test - 0x01 Command - Stop motors");
HBXStop2Motors();
// Read status
dbgSerial.println("");
dbgSerial.println("2 Test - Read Status");
HBXGet2Status();
// Stop the motors (Az and Alt)
dbgSerial.println("Test - Stop motors");
HBXStop2Motors();
dbgSerial.println("Test - End of Loop");
}
void HBXPrintSpeed(unsigned int count, unsigned int duration) {
int j = 0;
axis[AzMotor].Position = ETX_CENTRE; // Reset position
axis[AltMotor].Position = ETX_CENTRE;
axis[AzMotor].Increment = 0;
axis[AltMotor].Increment = 0;
PreviousTime = millis();
dbgSerial.print("Az, ");
dbgSerial.println(axis[AzMotor].Speed);
dbgSerial.print("Alt, ");
dbgSerial.println(axis[AltMotor].Speed);
HBXStart2Motors(); // Start the motors
do {
ETXState(AzMotor); // Check the Az motor state
ETXState(AltMotor); // Check the Alt motor state
dbgSerial.print(millis() - PreviousTime);
dbgSerial.print(", ");
SendSpeed(duration); // Duration is delay between reads
j += 1;
while ((millis() - PreviousTime) < duration);
PreviousTime = millis();
} while(j < count);
}
void SendSpeed(unsigned long duration) {
HBXGetStatus(AzMotor);
axis[AzMotor].Increment = axis[AzMotor].HBXP1 * 256 + axis[AzMotor].HBXP2;
HBXGetStatus(AltMotor);
axis[AltMotor].Increment = axis[AltMotor].HBXP1 * 256 + axis[AltMotor].HBXP2;
dbgSerial.println("");
dbgSerial.print("Az-Speed: ");
dbgSerial.print(axis[AzMotor].Speed);
dbgSerial.print(",Posn: ");
dbgSerial.print(axis[AzMotor].Position);
dbgSerial.print(",Incr: ");
dbgSerial.println(axis[AzMotor].Increment);
dbgSerial.print("Alt-Speed: ");
dbgSerial.print(axis[AltMotor].Speed);
dbgSerial.print(",Posn: ");
dbgSerial.print(axis[AltMotor].Position);
dbgSerial.print(",Incr: ");
dbgSerial.println(axis[AltMotor].Increment);
}
void HBXPrintPosn(unsigned int count, unsigned int duration) {
int j = 0;
axis[AzMotor].Position = ETX_CENTRE; // Reset position
axis[AltMotor].Position = ETX_CENTRE;
axis[AzMotor].Increment = 0;
axis[AltMotor].Increment = 0;
PreviousTime = millis();
HBXStart2Motors(); // Start the motors
do {
ETXState(AzMotor); // Check the Az motor state
ETXState(AltMotor); // Check the Alt motor state
SendData(duration); // Duration is delay between reads
j += 1;
} while(j < count);
}
void SendData(unsigned int duration) {
// dbgSerial.println(" SendPosn");
while ((millis() - PreviousTime) < duration) ; // 1/10 second
dbgSerial.print(millis() - PreviousTime);
dbgSerial.print(" - ");
PreviousTime = millis();
HBXGetStatus(AzMotor);
axis[AzMotor].Increment = axis[AzMotor].HBXP1 * 256 + axis[AzMotor].HBXP2;
HBXGetStatus(AltMotor);
axis[AltMotor].Increment = axis[AltMotor].HBXP1 * 256 + axis[AltMotor].HBXP2;
dbgSerial.print("Az = ");
dbgSerial.print(axis[AzMotor].Position);
dbgSerial.print(" : ");
dbgSerial.print(axis[AzMotor].Increment);
dbgSerial.print(", Alt = ");
dbgSerial.print(axis[AltMotor].Position);
dbgSerial.print(" : ");
dbgSerial.println(axis[AltMotor].Increment);
}
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(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) {
// dbgSerial.print(", Data: ");
// dbgSerial.print(axis[Motor].HBXP1, HEX);
if (axis[Motor].HBXCount > 1) dbgSerial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
// dbgSerial.print(axis[Motor].HBXP2, HEX);
if (axis[Motor].HBXCount > 1) dbgSerial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
// dbgSerial.print(axis[Motor].HBXP3, HEX);
if (axis[Motor].HBXCount > 1) dbgSerial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
// dbgSerial.print(axis[Motor].HBXP4, HEX);
axis[Motor].HBXCount -= 1;
}
// dbgSerial.println("");
}
}
bool HBXStop2Motors(void) {
axis[AzMotor].ETXMotorState = ETXStopMotor;
ETXState(AzMotor);
axis[AltMotor].ETXMotorState = ETXStopMotor;
ETXState(AltMotor);
return(true);
}
bool HBXStart2Motors(void) {
axis[AzMotor].ETXMotorState = ETXCheckStartup;
axis[AzMotor].EQGMotorStatus |= MOVEAXIS;
dbgSerial.print("Az, ");
dbgSerial.println(axis[AzMotor].Speed);
ETXState(AzMotor);
dbgSerial.print("Az, ");
dbgSerial.println(axis[AzMotor].Speed);
axis[AltMotor].ETXMotorState = ETXCheckStartup;
axis[AltMotor].EQGMotorStatus |= MOVEAXIS;
dbgSerial.print("Az, ");
dbgSerial.println(axis[AzMotor].Speed);
ETXState(AltMotor);
dbgSerial.print("Az, ");
dbgSerial.println(axis[AzMotor].Speed);
return(true);
}
void HBXPrintPosn(unsigned char Motor) {
if (Motor == MotorAz) {
dbgSerial.println("");
dbgSerial.print("Time: ");
dbgSerial.print(millis());
// dbgSerial.print(StatusTimer - StatusTime);
// StatusTime = StatusTimer;
/* dbgSerial.print(" AzRaw: ");
puthexb(axis[AzMotor].HBXP1);
putbyte(',');
puthexb(axis[AzMotor].HBXP2);
putbyte(',');
puthexb(axis[AzMotor].HBXP3);
putbyte(',');
puthexb(axis[AzMotor].HBXP4);
*/
dbgSerial.print(" AzPosn: ");
puthexl(axis[AzMotor].Position);
putbyte(',');
puthexl(axis[AzMotor].Target);
putbyte(',');
puthexl(axis[AzMotor].SlowDown);
dbgSerial.print(" AzSpeed: ");
puthexl(axis[AzMotor].Speed);
putbyte(',');
puthexl(axis[AzMotor].TargetSpeed);
putbyte('-');
puthexw(axis[AzMotor].EQGMotorStatus);
putbyte(',');
puthexw(axis[AzMotor].MotorControl);
}
else {
/*
* dbgSerial.print(" AltRaw: ");
puthexb(axis[AltMotor].HBXP1);
putbyte(',');
puthexb(axis[AltMotor].HBXP2);
putbyte(',');
puthexb(axis[AltMotor].HBXP3);
putbyte(',');
puthexb(axis[AltMotor].HBXP4);
*/
dbgSerial.print(" AltPosn: ");
puthexl(axis[AltMotor].Position);
putbyte(',');
puthexl(axis[AltMotor].Target);
putbyte(',');
puthexl(axis[AltMotor].SlowDown);
dbgSerial.print(" AltSpeed: ");
puthexl(axis[AltMotor].Speed);
putbyte(',');
puthexl(axis[AltMotor].TargetSpeed);
putbyte('-');
puthexw(axis[AltMotor].EQGMotorStatus);
putbyte(',');
puthexw(axis[AltMotor].MotorControl);
dbgSerial.println("");
}
}