pull/1/head
ozarchie 2018-01-02 17:43:58 +10:00 zatwierdzone przez GitHub
rodzic f43011aeb5
commit 5ac06ecce8
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
10 zmienionych plików z 2521 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,150 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG2HBX program definitions
===========================
*********************************************************/
#ifndef EQG2HBX
#define EQG2HBX
// Real Time Clock Libraries
// Time related libararies
#include <DS1307RTC.h> //https://www.pjrc.com/teensy/td_libs_DS1307RTC.html
#include <TimeLord.h> //https://github.com/probonopd/TimeLord
#include <TimeLib.h> //https://github.com/PaulStoffregen/Time
#include <TimeAlarms.h> //https://github.com/PaulStoffregen/TimeAlarms
// Pin definitions for LED indicators
// ==================================
#define AzLED 7 // Mega2560 D7
#define AltLED 6 // Mega2560 D6
#define FROMEQG 5 // Mega2560 D5
#define FROMHBX 4 // Mega2560 D4
// Jumpers to run monitor or test
// ==============================
#define TESTHBX 9 // Mega2560 D2
#define MONITORHBX 11 // Mega2560 D3
/**************************************************************
* Common variables
**************************************************************/
unsigned long DelayTimer = 0; // Delay timer
unsigned long StatusTimer = 0; // H2X delay timer
unsigned long StatusTime = 0; // H2X interval time
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 EQGDbgBuffer[EQGLEN]; // Debug
unsigned char EQGDbgPtr = 0; // Pointer for debug
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
unsigned char EQGDbgCount; // EQG # parameters
/**************************************************************
* 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 MotorStatus; // 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 HBXMotorStatus; // Current HBX Motor State
unsigned long HBXMotorControl; // Current HBX Motor Control bits
unsigned char HBXBitCount; // #bits left to process
unsigned char HBXCmnd; // Current command
unsigned char HBXData; // Data byte from HBX Bus
unsigned char HBXP1; // HBX status/data - MSB
unsigned char HBXP2; // HBX status/data
unsigned char HBXP3; // HBX status/data - LSB
unsigned char HBXP4; // HBX status/data - encoder error
unsigned char HBXCount; // HBX valid data count
unsigned char HBXLEDI; // LED current value from Motor
unsigned long HBXDirSpeed; // Speed, Direction for Motor to move
char HBXGuide; // Guide speed
long HBXSpeed; // Move speed
long HBXTargetSpeed; // Target Move speed
char HBXSpeedState; // Slowdown/speedup state
long HBXPosn; // Current position
long HBXTarget; // Current target delta
long HBXDelta; // Change in position for motor speed calcs
long HBXSlowDown; // Point to change to lower speed
long HBXOffset; // Current adjustment
long HBX_bVALUE; // For rate calculations
unsigned long SIDEREALRATE; // Constants
unsigned long SOLARRATE;
unsigned long LUNARRATE;
unsigned long DEGREERATE1;
unsigned long DEGREERATE2;
unsigned long SIDEREALSPEED;
unsigned long SOLARSPEED;
unsigned long LUNARSPEED;
unsigned long DEGREESPEED1;
unsigned long DEGREESPEED2;
unsigned long STEPSPER360;
unsigned long WORM;
unsigned long PEC;
unsigned char PrintStatus0; // Force print of no status change
unsigned long TimeDelta; // Used in HBX Monitor
} axis_type;
axis_type axis[4]; // Az, Alt
unsigned long PreviousTime; // Used in HBX Monitor, Testing
// Testing only
unsigned char TestCount;
unsigned long TestLoopTime;
// Monitor only
unsigned char DetectedClock;
#endif

Wyświetl plik

@ -0,0 +1,272 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
Initialize HBX, translate EQG to HBX
====================================
*********************************************************/
#include <Arduino.h>
#include <EEPROM.h>
#include "EQGProtocol.h"
#include "ETXProtocol.h"
#include "HBXComms.h"
#include "EQG2HBX.h" // All the declared variables
void setup()
{
int i, j, k;
bool b;
DelayTimer = micros(); // Initialize timers, counts
StatusTimer = DelayTimer;
StatusTime = DelayTimer;
TestCount = 0;
EQGErrorValue = 0;
pinMode(FROMEQG, OUTPUT); // Initialize Indicator pins
pinMode(FROMHBX, OUTPUT);
pinMode(AzLED, OUTPUT);
pinMode(AltLED, OUTPUT);
digitalWrite(FROMEQG, LOW); // Initialize Indicator LEDS
digitalWrite(FROMHBX, LOW);
digitalWrite(AzLED, LOW);
digitalWrite(AltLED, LOW);
pinMode(MONITORHBX, INPUT_PULLUP); // Initialize Operation jumpers
pinMode(TESTHBX, INPUT_PULLUP);
digitalWrite(MONITORHBX, HIGH);
digitalWrite(TESTHBX, HIGH);
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
Serial.begin(115200); // Debug
Serial.println("ETX V5.01");
Serial1.begin(9600); // EQMOD
Serial1.println("ETX-EQMOD");
Serial2.begin(9600);
Serial3.begin(9600);
Serial.print("EEPROM length: ");
Serial.println(EEPROM.length());
Serial.print("CRC32 of EEPROM data: 0x");
Serial.print(eeprom_crc(), HEX);
if (!check_eeprom_crc()) {
Serial.println(" - crc failed");
set_eeprom_crc();
check_eeprom_crc();
}
else Serial.println(" - crc OK");
// **************************
// Check for HBX Monitor Mode
// ==========================
if (digitalRead(MONITORHBX) == 0) { // Check if monitor jumper installed
HBXMonitorLoop(); // Execute monitor code until jumper removed
}
// **************************
// Check for HBX Testing Mode
// ==========================
if (digitalRead(TESTHBX) == 0) { // Check if test jumper installed
HBXTestLoop(); // Execute test code until jumper removed
}
while (digitalRead(TESTHBX) == 0) {
Serial.println("Test HBX commands to ETX");
HBXTest();
TimerDelaymS(5000);
}
Serial.println("HBX Initialization");
AzInitialise();
AltInitialise();
// Initialize HBX communications as outputs
// It will use H2X communications
HCL1Talk(); // Set for Talking on RAClk
HCL2Talk(); // Set for Talking on DECClk
HDAListen();
TimerDelaymS(STARTTIME);
// Reset the motors (RA and DEC)
// and wait until both respond to a command
Serial.println("Wait for both motors to start up");
WaitForMotors();
// Get Motor Type from Az MC ( assume both same type of motor)
Serial.print("Get Motor Type: ");
do {
axis[AzMotor].MotorType = 0x00;
if (HBXSendCommand(GetMotorType, AzMotor))
axis[AzMotor].MotorType = HBXGetByte(AzMotor);
} while (!axis[AzMotor].MotorType);
axis[AltMotor].MotorType = axis[AzMotor].MotorType;
Serial.println(axis[AltMotor].MotorType);
// Get the real LEDI values from EEPROM
axis[AzMotor].HBXLEDI = EEPROM.read(EEPROMAzLEDI);
axis[AltMotor].HBXLEDI = EEPROM.read(EEPROMAltLEDI);
// Set LED values from EEPROM
Serial.print("Set Encoder LED currents - Az: ");
if (HBXSendCommand(SetLEDI, AzMotor))
HBXSendByte(axis[AzMotor].HBXLEDI, AzMotor);
if (HBXSendCommand(SetLEDI, AltMotor))
HBXSendByte(axis[AltMotor].HBXLEDI, AltMotor);
Serial.print(axis[AzMotor].HBXLEDI);
Serial.print(", Alt: ");
Serial.println(axis[AltMotor].HBXLEDI);
// Set the Offset Clear Command
// Send HBXP1, HBXP2 - which were initialised to 0
Serial.println("Reset any ETX offset bytes");
if (HBXSendCommand(SetOffset, AzMotor))
HBXSend2Bytes(AzMotor);
TimerDelaymS(CMNDTIME);
if (HBXSendCommand(SetOffset, AltMotor))
HBXSend2Bytes(AltMotor);
TimerDelaymS(CMNDTIME);
// Stop the motors (RA and DEC)
Serial.println("Stop motors");
do {
P1 = 0;
if (HBXSendCommand(Stop, AzMotor)) P1 += 1;
if (HBXSendCommand(Stop, AltMotor)) P1 += 1;
} while (P1 < 2);
// Read status
Serial.println("Read Status");
HBXGet2Status(); // Check and read both motor states
currentTime = now();
Serial.println("Setup Complete. Listening for commands ..");
// Print debug info every 5 s
// --------------------------
Alarm.timerRepeat(10, debugEQG); // Every 10 seconds
}
void loop()
{
/**************************************************************************************************
* Check ETXState
**************************************************************************************************/
if ((micros() - DelayTimer) > 6550) {
DelayTimer = micros();
HBXGet2Status(); // Polls motor position every 6.55mS
}
ETXState(AzMotor); // Check the Az motor state
ETXState(AltMotor); // Check the Alt motor state
/**************************************************************************************************
* Process EQG comms - Rx Comms are interrupt driven
**************************************************************************************************/
EQGRx(); // Check for comms from EQG
EQGState(); // Check command state
if (EQGDone) { // EQG receive complete, see what it is
if (EQGErrorValue == 0) {
EQGAction(); // and do it
}
else {
EQGError(EQGErrorValue); // EQGAction() may set an error
}
}
while (EQGTxoPtr != EQGTxiPtr) { // EQG send any response
Serial1.write(EQGTxBuffer[EQGTxoPtr++]); // Output to EQG
EQGTxoPtr &= EQGMASK;
}
Alarm.delay(0);
} // End loop()
/**************************************************************************************************
* 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);
}
/**********************************************
EEPROM support
***********************************************/
unsigned long eeprom_crc(void) {
const unsigned long crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned long crc = ~0L;
for (int index = 0 ; index < (EEPROM.length()-4) ; ++index) {
crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);
crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);
crc = ~crc;
}
return crc;
}
unsigned long get_eeprom_crc(void) {
unsigned long crc;
int i;
i = EEPROM.length()-4; // Location of stored crc (last four bytes)
crc = 0;
for (int j = 0; j < 4; j++) {
crc = crc << 8;
crc = crc | EEPROM.read(i);
i += 1;
}
return (crc);
}
bool set_eeprom_crc(void) {
unsigned long crc;
unsigned char data;
int i;
i = EEPROM.length()-1; // Location of stored crc (last four bytes)
crc = eeprom_crc();
for (int j = 0; j < 4; j++) {
data = crc & 0xFF;
EEPROM.write(i, data);
if (EEPROM.read(i) != data) return (false);
i -= 1;
crc = crc >> 8;
}
return (true);
}
bool check_eeprom_crc(void) {
if (eeprom_crc() == get_eeprom_crc()) return true;
else return false;
}

Wyświetl plik

@ -0,0 +1,83 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG Protocol function definitions
=================================
*********************************************************/
#ifndef EQGProtocol
#define EQGProtocol
#define CR 0x0d
#define LF 0x0a
#define SIDEREALSECS 86164 // Some astronomical constants
#define SOLARSECS 86400
#define LUNARSECS 89309
#define ARCSECS 360*60*60
#define EQG_CMNDSTART 0x01
#define EQG_WAITFORCR 0x77
#define EQG_INTERPRET 0x78
#define EQGVERSION 0x000501 // Simulate EQ6
#define EQG_CENTRE ETX_CENTRE
#define EQG_RAbVALUE AzSIDEREALRATE*(AzSTEPSPER360/SIDEREALSECS)
#define EQG_DECbVALUE AltSIDEREALRATE*(AzSTEPSPER360/SIDEREALSECS)
#define EQG_gVALUE 0x00000010
#define EQGMAXIMUMSPEED 12 // 0x0C
// EQG 'G' Command - SET move parameters
#define DIRECTION 0x0001 // N/E(0) S/W(1)
//#define HEMISPHERE 0x0002 // North(0) South(1)
//#define SLEWSTEP 0x0010 // Slew(0) Step(1)
//#define HIGHLOW 0x0020 // High(0) Low(1)
// 3 HIGH SPEED SLEW
// 2 LOW SPEED GOTO
// 1 LOW SPEED SLEW
// 0 HIGH SPEED GOTO
// EQG 'f' Command - GET Motor status bit definitions
// MotorState bit definitions
// nibble 1
#define MOVESTEP 0x0001 // Slew(0) Step(1)
#define MOVEDIRN 0x0002 // Decreasing(0) Increasing(1)
#define MOVELOW 0x0004 // High(0) Low(1)
// nibble2
#define MOVEAXIS 0x0010 // Stopped(0) Moving(1)
#define MOVEFACE 0x0020 // Front(0) Rear(1)
// nibble3
#define COILACTIVE 0x0100 // Inactive(0) Active(1)
#define FORWARD MOVEDIRN
#define REVERSE 0
void EQGState(void);
void EQGError(unsigned char);
void EQGAction(void);
void TimerDelaymS(unsigned long);
void 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,555 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG Protocol related functions
==============================
*********************************************************/
// Process received EQG characters
// ===============================
void EQGState(void) {
while ((EQGRxiPtr != EQGRxoPtr) && (EQGDone == 0)) {
digitalWrite(FROMEQG, HIGH); // Set Indicator LED
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) { // Need data?
case 'A': // Unknown
case 'B': // Unknown
case 'E': // Set Current Position
case 'G': // Set Move direction and speed multiplier
case 'H': // Set Target Position
case 'I': // Set GOTO Speed
case 'M': // Set Mount Motor Change Speed
case 'P': // Set the AutoGuide Speed
case 'R': // Unknown
case 'S': // Unknown
case 'T': // Unknown
case 'U': // Unknown
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) { // Need to get more data?
case 'B': // B only takes one nibble
case 'P': // P only takes one nibble
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) { // Need to get more data?
case 'A': // A unknown
case 'G': // G Set direction, range
case 'R': // R unknown
EQGRxState = EQG_INTERPRET;
break;
default:
EQGRxState++;
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++;
EQGRxState++; // Get next data
break;
case 0x08: // Fifth nibble - N5xxN3N4N1N2
EQGP2 = EQGRxChar;
EQGRxCount++;
EQGP1 |= (EQGP2 << 20);
EQGRxState++; // Get next data
break;
case 0x09: // Sixth nibble - N5N6N3N4N1N2
EQGP2 = EQGRxChar;
EQGRxCount++;
EQGP1 |= (EQGP2 << 16);
EQGRxState = EQG_INTERPRET; // All done
break;
case EQG_INTERPRET:
if ((EQGRxChar == 0x0d) && (EQGRxCount >= 3)) {
EQGRxState = EQG_CMNDSTART; // Reset state machine
switch (EQGCmnd) {
// Commands that need no data
case 'a': // Read steps per rotation
case 'b': // Read tracking scale
case 'c': // Read Motor Speed Change
case 'd': //
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 's': // Read steps per arcsec
case 'D': // Read track rate
case 'F': // Initialize motors
case 'J': // GoTo position, track
case 'K': // Stop movement
EQGDone++;
break;
// Commands that need data
case 'E': // Set current position
case 'H': // Set target position
case 'I': // Set GoTo speed
case 'M': // Set motor slowdown position
if (EQGRxCount == (3 + 6)) {
EQGDone++;
}
else {
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
else EQGDone++;
EQGErrorValue = '3'; // Failure - Bad Parameters
}
break;
case 'G': // Set direction and range
if (EQGRxCount == (3 + 2)) {
EQGDone++;
}
else {
if (EQGRxChar != 0x0d) EQGRxState = EQG_WAITFORCR;
else EQGDone++;
EQGErrorValue = '3'; // Failure - Bad Parameters
}
break;
case 'P': // Set autoguide speed
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))
digitalWrite(FROMEQG, LOW); // Clear Indicator LED
}
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;
digitalWrite(FROMEQG, HIGH); // and status LED
EQGTx('='); // Answer (with parameters)
switch (EQGCmnd) {
case 'a': // Request total number of steps per revolution
EQGTxHex6(axis[EQGMOTOR].STEPSPER360);
break;
case 'b': // Request step interrupt frequency
EQGTxHex6(axis[EQGMOTOR].HBX_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
break;
case 'e': // Request version
EQGTxHex6(EQGVERSION); // V5.01
break;
case 'f': // Request motor status
// MotorState bit definitions
// nibble 1
// MOVESTEP 0x0001 // Slew(0) Step(1)
// MOVEDIRN 0x0002 // Decreasing(0) Increasing(1)
// MOVELOW 0x0004 // Low(0) High(1)
// nibble2
// MOVEAXIS 0x0010 // Stopped(0) Moving(1)
// MOVEFACE 0x0020 // Front(0) Rear(1)
// nibble3
// COILACTIVE 0x0100 // Inactive(0) Active(1)
EQGTxHex3(axis[EQGMOTOR].HBXMotorStatus);
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].HBXPosn);
break;
case 'm': // GET Point at which to change from fast to slow
EQGTxHex6(axis[EQGMOTOR].HBXSlowDown);
break;
case 's': // PEC period
EQGTxHex6(axis[EQGMOTOR].PEC);
break;
case 'E': // Set current motor position
axis[EQGMOTOR].HBXPosn = EQGP1;
break;
case 'F': // Initialize and activate motors
axis[EQGMOTOR].HBXMotorStatus |= COILACTIVE;
break;
case 'G': // EQG 'G' Command - SET move parameters
// DIRECTION 0x0001 // N/E(0) S/W(1)
// HEMISPHERE?? 0x0002 // North(0) South(1)
axis[EQGMOTOR].HBXDirSpeed = (int)EQGP1; // Save the actual value
if (EQGP1 & DIRECTION) // Set direction bit
axis[EQGMOTOR].HBXMotorStatus &= ~MOVEDIRN;
else
axis[EQGMOTOR].HBXMotorStatus |= MOVEDIRN;
// SLEWSTEP 0x0010 // Slew(0) Step(1)
// HIGHLOW 0x0020 // High(0) Low(1)
switch ((EQGP1 >> 4) & 0x03) {
case 00: // 0 HIGH SPEED SLEW
axis[EQGMOTOR].HBXMotorStatus &= ~MOVESTEP;
axis[EQGMOTOR].HBXMotorStatus &= ~MOVELOW;
break;
case 01: // 1 HIGH SPEED STEP
axis[EQGMOTOR].HBXMotorStatus |= MOVESTEP;
axis[EQGMOTOR].HBXMotorStatus &= ~MOVELOW;
break;
case 02: // 2 LOW SPEED GOTO
axis[EQGMOTOR].HBXMotorStatus &= ~MOVESTEP;
axis[EQGMOTOR].HBXMotorStatus |= MOVELOW;
break;
case 03: // 3 LOW SPEED STEP
axis[EQGMOTOR].HBXMotorStatus |= MOVESTEP;
axis[EQGMOTOR].HBXMotorStatus |= MOVELOW;
break;
}
break;
case 'H': // SetGotoTargetIncrement(AXISID Axis, long StepsCount)
axis[EQGMOTOR].HBXDelta = EQGP1;
if ((axis[EQGMOTOR].HBXMotorStatus & MOVEDIRN) == FORWARD)
axis[EQGMOTOR].HBXTarget = axis[EQGMOTOR].HBXPosn + axis[EQGMOTOR].HBXDelta; // add the relative target
else
axis[EQGMOTOR].HBXTarget = axis[EQGMOTOR].HBXPosn - axis[EQGMOTOR].HBXDelta; // subtract the relative target
Serial.println("");
Serial.print("HBX:<");
Serial.print(EQGMOTOR);
Serial.print("-");
Serial.print(axis[EQGMOTOR].HBXMotorStatus, HEX);
Serial.print("> ");
Serial.print(", Pos: ");
Serial.print(axis[EQGMOTOR].HBXPosn, HEX);
Serial.print(", Del: ");
Serial.print(axis[EQGMOTOR].HBXDelta, HEX);
Serial.print("->Tgt: ");
Serial.print(axis[EQGMOTOR].HBXTarget, HEX);
axis[EQGMOTOR].HBXMotorControl |= MoveHBX; // Signal pending move
break;
case 'I': // Set motor speed
if ( EQGP1 == 0x177C ) { // axis[EQGMOTOR].SIDEREALRATE) {
EQGP1 = axis[EQGMOTOR].SIDEREALRATE;
}
else if ( EQGP1 == 0x1785 ) { // axis[EQGMOTOR].SOLARRATE) {
EQGP1 = axis[EQGMOTOR].SOLARRATE;
}
else if ( EQGP1 == 0x185B ) { // axis[EQGMOTOR].LUNARRATE) {
EQGP1 = axis[EQGMOTOR].LUNARRATE;
}
else {
if (axis[EQGMOTOR].HBXMotorStatus & MOVELOW) { // 1 -> HIGH
// EQG is (400, 480, 600, 800)
// value: 18, 14, 10, 0c
// Map 800 to 2 degrees / sec
EQGF1 = (float)EQGMAXIMUMSPEED / (float)EQGP1; // Scale to maximum EQG speed
EQGF1 = EQGF1 * (float)axis[EQGMOTOR].DEGREESPEED2; // Multiply by maximum ETX speed
}
else { // EQG is (.5, 1, 2, 8, .. 64) * Sidereal
EQGF1 = EQGF1 * (float)axis[EQGMOTOR].SIDEREALSPEED; // Multiply by Sidereal ETX speed
}
EQGP1 = (unsigned long) EQGF1; // Convert to ETX format
EQGP2 = (unsigned long) ((EQGF1 - float(EQGP1)) * 65536L);
EQGP1 = ((EQGP1 << 16) & 0xFF0000); // Format to 8.16 rate
EQGP1 |= (EQGP2 & 0xFFFF);
}
axis[EQGMOTOR].HBXSpeed = EQGP1; // Set the speed
break;
case 'J': // Tell motor to Go
axis[EQGMOTOR].HBXMotorStatus |= MOVEAXIS; // Signal moving
break;
case 'K': // Tell motor to stop
axis[EQGMOTOR].ETXMotorState = ETXStopMotor;
break;
case 'M': // SetBreakPointIncrement(AXISID Axis, long StepsCount)
axis[EQGMOTOR].HBXSlowDown = EQGP1;
if ((axis[EQGMOTOR].HBXMotorStatus & MOVEDIRN) == FORWARD)
axis[EQGMOTOR].HBXSlowDown = axis[EQGMOTOR].HBXTarget + axis[EQGMOTOR].HBXSlowDown; // add the relative target
else
axis[EQGMOTOR].HBXSlowDown = axis[EQGMOTOR].HBXTarget - axis[EQGMOTOR].HBXSlowDown; // subtract the relative target
Serial.println("");
Serial.print("HBX:<");
Serial.print(EQGMOTOR);
Serial.print("-");
Serial.print(axis[EQGMOTOR].HBXMotorStatus, HEX);
Serial.print("> ");
Serial.print(", Pos: ");
Serial.print(axis[EQGMOTOR].HBXPosn, HEX);
Serial.print(", Del: ");
Serial.print(EQGP1, HEX);
Serial.print("-> SD: ");
Serial.println(axis[EQGMOTOR].HBXSlowDown, HEX);
break;
case 'P':
axis[EQGMOTOR].HBXGuide = (char)EQGP1;
break;
default:
EQGErrorValue = '0'; // Failure - Bad Command
break;
}
EQGTx(CR);
digitalWrite(FROMEQG, LOW); // Clear Indicator LED
}
/**********************************************
Handle EQG communications
***********************************************/
void EQGRx(void) {
while (Serial1.available() > 0) {
EQGRxBuffer[EQGRxiPtr++] = Serial1.read();
EQGRxiPtr &= EQGMASK;
}
}
void EQGTx(unsigned char data) {
EQGTxBuffer[EQGTxiPtr++] = data;
EQGTxiPtr &= EQGMASK;
}
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 putbyte(unsigned char data) {
Serial.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) {
Serial.print(data);
}
void puthexw(unsigned int data) {
puthexb((data>>8) & 0xFF);
puthexb(data & 0xFF);
}
void putdecw(unsigned int data) {
Serial.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) {
Serial.print(data);
}
void EQGSend(unsigned char data) {
Serial.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() {
Serial.println("");
Serial.print("Az:<");
Serial.print(axis[AzMotor].HBXMotorStatus, HEX);
Serial.print(">Pos: ");
Serial.print(axis[AzMotor].HBXPosn, HEX);
Serial.print(" SD: ");
Serial.print(axis[AzMotor].HBXSlowDown, HEX);
Serial.print(" Tgt: ");
Serial.print(axis[AzMotor].HBXTarget, HEX);
Serial.print(", Alt:<");
Serial.print(axis[AzMotor].HBXMotorStatus, HEX);
Serial.print(">Pos: ");
Serial.print(axis[AltMotor].HBXPosn, HEX);
Serial.print(" SD: ");
Serial.print(axis[AltMotor].HBXSlowDown, HEX);
Serial.print(" Tgt: ");
Serial.print(axis[AltMotor].HBXTarget, HEX);
}

Wyświetl plik

@ -0,0 +1,116 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
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].HBXMotorControl
// nibble 4
#define StartHBX 0x8000 // Motor start bit
#define StopHBX 0x4000 // Motor stop bit
#define MoveHBX 0x2000 // Move pending
#define SpeedHBX 0x1000 // Speed change pending
#define GoToHBX 0x0800 // GoTo in Progress
// ETX Known Commands
#define RotateSlow 0x00 // Output "8.16" speed
#define RotateFast 0x01 // Output "16.8" ? 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 ResetH2X 0xE4 // None
// ETX State Machine
#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
#define EEPROMAzLEDI 0x01 // EEPROM Storage
#define EEPROMAltLEDI 0x02
#define EEPROMMotor 0x03 // MOTOR TYPE
#define ETX60PERIOD 152.587891 // (1/6.55mS)
#define ETX_CENTRE 0x00800000
#define AzSTEPSPER360 1233750 // See etx60at-gears.ods
#define AltSTEPSPER360 1315440
#define AzWORM 94
#define AltWORM 58
#define AzPEC AzSTEPSPER360/AzWORM
#define AltPEC AltSTEPSPER360/AltWORM
#define AzSIDEREALRATE 0x001805 // (AzSTEPSPER360/SIDEREALSECS)/ETX60PERIOD
#define AzSOLARRATE 0x0017F5 // (AzSTEPSPER360/SOLARSECS)/ETX60PERIOD
#define AzLUNARRATE 0x00172D // (AzSTEPSPER360/LUNARSECS)/ETX60PERIOD
#define AzDEGREERATE1 0x1675B1 // (AltSTEPSPER360/360)/ETX60PERIOD
#define AzDEGREERATE2 AzDEGREERATE1 << 1
#define AltSIDEREALRATE 0x00199C // (AltSTEPSPER360/SIDEREALSECS)/ETX60PERIOD
#define AltSOLARRATE 0x00198B // (AzSTEPSPER360/SOLARSECS)/ETX60PERIOD
#define AltLUNARRATE 0x0018B6 // (AzSTEPSPER360/LUNARSECS)/ETX60PERIOD
#define AltDEGREERATE1 0x17F265 // (AzSTEPSPER360/360)/ETX60PERIOD
#define AltDEGREERATE2 AltDEGREERATE1 << 1
#define AzSIDEREALSPEED 0.09383854 // (AzSTEPSPER360/SIDEREALSECS)/ETX60PERIOD
#define AzSOLARSPEED 0.09358222 // (AzSTEPSPER360/SOLARSECS)/ETX60PERIOD
#define AzLUNARSPEED 0.09053403 // (AzSTEPSPER360/LUNARSECS)/ETX60PERIOD
#define AzDEGREESPEED1 22.4597 // (AzSTEPSPER360/360)/ETX60PERIOD
#define AzDEGREESPEED2 AzDEGREESPEED1 * 2.0
#define AltSIDEREALSPEED 0.10005185 // (AltSTEPSPER360/SIDEREALSECS)/ETX60PERIOD
#define AltSOLARSPEED 0.09977856 // (AzSTEPSPER360/SOLARSECS)/ETX60PERIOD
#define AltLUNARSPEED 0.09652854 // (AzSTEPSPER360/LUNARSECS)/ETX60PERIOD
#define AltDEGREESPEED1 23.9469 // (AltSTEPSPER360/360)/ETX60PERIOD
#define AltDEGREESPEED2 AltDEGREESPEED1 * 2.0
#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 360 // 90 arc-min/sec or 1.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 HBXSetMotorState(unsigned char);
bool HBXCheckTargetStatus(unsigned char);
bool HBXUpdatePosn(void);
bool HBXStartMotor(unsigned char);
bool HBXStopMotor(unsigned char);
bool HBXGetStatus(unsigned char);
void HBXPosnPoll(unsigned char);
#endif

Wyświetl plik

@ -0,0 +1,344 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
ETX Protocol related functions
==============================
*********************************************************/
bool ETXState(unsigned char Motor) {
long c, d;
long l1;
int s1;
switch(axis[Motor].ETXMotorState) {
case ETXCheckStartup:
if (axis[Motor].HBXMotorStatus & MOVEAXIS) { // Are we moving?
if (axis[EQGMOTOR].HBXMotorStatus & MOVESTEP) { // Step or Slew
axis[Motor].ETXMotorState = ETXStepMotor;
}
else {
if (axis[Motor].HBXDelta > 0x800) // Slew large enough for ETX slew?
axis[Motor].ETXMotorState = ETXSlewMotor; // Yes, go
else {
axis[EQGMOTOR].HBXMotorStatus |= MOVESTEP; // No, change to step
if (axis[EQGMOTOR].HBXDelta < 0x100) { // Scale speed down for really small slews
axis[Motor].HBXTargetSpeed = axis[Motor].HBXTargetSpeed >> 2;
}
axis[Motor].HBXSpeed = 0;
axis[Motor].ETXMotorState = ETXStepMotor;
}
}
}
break;
case ETXSlewMotor:
if (Motor == MotorAz) digitalWrite(AzLED, HIGH); // Turn on the LED
else digitalWrite(AltLED, HIGH);
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == FORWARD)
axis[Motor].HBXCmnd = SlewForward;
else
axis[Motor].HBXCmnd = SlewReverse;
if (!(HBXSendCommand(axis[Motor].HBXCmnd, Motor))) {
axis[Motor].ETXMotorState = ETXCheckStartup; // Motor failed to start
}
else
axis[Motor].ETXMotorState = ETXCheckSlowDown;
break;
case ETXStepMotor:
if (Motor == MotorAz) digitalWrite(AzLED, HIGH); // Turn on the LED
else digitalWrite(AltLED, HIGH);
if (axis[Motor].HBXMotorStatus & MOVELOW) // Stepping, High or Low speed
axis[Motor].HBXCmnd = RotateSlow;
else axis[Motor].HBXCmnd = RotateFast;
if (axis[Motor].HBXSpeed == 0) { // Starting up
axis[Motor].HBXSpeed = axis[Motor].HBXTargetSpeed >> 2;
}
// Set the speed, and direction
// ----------------------------
P1 = axis[Motor].HBXSpeed;
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == REVERSE) // 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;
// Send the command
// ----------------
if (HBXSendCommand(axis[Motor].HBXCmnd, Motor)) // Command OK?
HBXSend3Bytes(Motor); // Send the speed
if (axis[Motor].HBXMotorControl & MoveHBX) {
axis[Motor].ETXMotorState = ETXCheckSpeed; // For a position move
}
else {
axis[Motor].ETXMotorState = ETXCheckStartup; // Just a speed command
axis[Motor].HBXMotorStatus &= ~MOVEAXIS; // Speed set, all done
}
break;
case ETXCheckSlowDown:
// Check if Slowdown reached
// Ramp-up speed til we get to slowdown point
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == FORWARD) { // Moving forwards
d = axis[Motor].HBXSlowDown;
c = axis[Motor].HBXPosn;
}
else { // Moving backwards
d = axis[Motor].HBXPosn;
c = axis[Motor].HBXSlowDown;
}
if ((c >= d) || ((d - c) < ETXSLOWPOSN)) { // Check distance to slowdown
axis[Motor].HBXSpeed = axis[Motor].DEGREERATE2; // Default slowdown 1st speed
axis[Motor].HBXTargetSpeed = 0; // Default slowdown target i.e. stopped
axis[Motor].HBXSpeedState = 0; // Speed ramp state
axis[Motor].HBXMotorStatus |= MOVESTEP; // Set the step flag
axis[Motor].ETXMotorState = ETXStepMotor; // GoTo speed ramp
}
break;
case ETXCheckSpeed:
// Speeding Up
// ===========
if ((axis[Motor].HBXTargetSpeed != 0) && (axis[Motor].HBXTargetSpeed > axis[Motor].HBXSpeed)) {
if ((axis[Motor].HBXTargetSpeed - axis[Motor].HBXSpeed) >= axis[Motor].DEGREERATE1) {
axis[Motor].HBXSpeed += ((axis[Motor].HBXTargetSpeed - axis[Motor].HBXSpeed) >> 2);
axis[Motor].ETXMotorState = ETXStepMotor;
}
else {
axis[Motor].HBXSpeed = axis[Motor].HBXTargetSpeed;
axis[Motor].ETXMotorState = ETXCheckPosition;
}
}
// Slowing Down
// ============
else {
if ((axis[Motor].HBXSpeed - axis[Motor].HBXTargetSpeed) >= axis[Motor].DEGREERATE1) {
axis[Motor].HBXSpeed -= ((axis[Motor].HBXSpeed - axis[Motor].HBXTargetSpeed) >> 2);
axis[Motor].ETXMotorState = ETXStepMotor;
}
else
axis[Motor].ETXMotorState = ETXCheckPosition;
}
break;
case ETXCheckPosition:
// Check if Target acquired
// ------------------------
// Calculate absolute distance to target
// -------------------------------------
if (axis[Motor].HBXMotorControl & MoveHBX) {
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == REVERSE) {
d = axis[Motor].HBXTarget;
c = axis[Motor].HBXPosn;
}
else {
c = axis[Motor].HBXTarget;
d = axis[Motor].HBXPosn;
}
l1 = c - d;
if (l1 >= 0) {
// Start to slow motor if getting near target
// ------------------------------------------
if ((l1 <= 0x400) && (axis[Motor].HBXSpeedState == 0)) {
axis[Motor].HBXSpeed = axis[Motor].HBXSpeed >> 1; // 1/2
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
axis[Motor].HBXSpeedState += 1;
}
else if ((l1 <= 0x100) && (axis[Motor].HBXSpeedState == 1)) {
axis[Motor].HBXSpeed = axis[Motor].HBXSpeed >> 1; // 1/4
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed
axis[Motor].HBXSpeedState += 1;
}
else if ((l1 <= 0x40) && (axis[Motor].HBXSpeedState == 2)) {
axis[Motor].HBXSpeed = axis[Motor].HBXSpeed >> 2; // 1/16
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed;
axis[Motor].HBXSpeedState += 1;
}
else if ((l1 <= 0x20) && (axis[Motor].HBXSpeedState == 3)) {
axis[Motor].HBXSpeed = axis[Motor].HBXSpeed >> 2; // 1/64
axis[Motor].ETXMotorState = ETXStepMotor; // Change speed;
axis[Motor].HBXSpeedState += 1;
}
else if (l1 <= 0x08) {
axis[Motor].ETXMotorState = ETXStopMotor; // Stop motor, next state
}
}
else {
// Motor has over-shot the target
// ------------------------------
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == FORWARD) // EQG -> change direction
axis[Motor].HBXMotorStatus &= ~FORWARD;
else
axis[Motor].HBXMotorStatus |= FORWARD;
// axis[Motor].HBXSpeed = TwosComplement(axis[Motor].HBXSpeed); // ETX invert speed
axis[Motor].ETXMotorState = ETXStepMotor; // Change ETX speed
}
}
else {
axis[Motor].ETXMotorState = ETXStopMotor;
}
break;
case ETXStopMotor:
while(!(HBXSendCommand(Stop, Motor))); // Stop the motor
axis[Motor].ETXMotorState = ETXMotorEnd; // Final state
break;
case ETXMotorEnd:
if (Motor == MotorAz) digitalWrite(AzLED, LOW); // Turn off the LED
else digitalWrite(AltLED, LOW);
if (axis[Motor].HBXMotorControl & MoveHBX) { // if we were moving
// Check we got there exactly
// --------------------------
if ((axis[Motor].HBXMotorStatus & MOVEDIRN) == REVERSE) {
d = axis[Motor].HBXTarget;
c = axis[Motor].HBXPosn;
}
else {
c = axis[Motor].HBXTarget;
d = axis[Motor].HBXPosn;
}
l1 = c - d;
// Set the offset
// ----------------------------
if (l1 != 0) {
axis[Motor].HBXP1 = (l1 >> 8) & 0xFF; // Initialize offset bytes
axis[Motor].HBXP2 = l1 & 0xFF;
axis[Motor].HBXCmnd = SetOffset;
if (HBXSendCommand(axis[Motor].HBXCmnd, Motor)) // Command OK?
HBXSend2Bytes(Motor); // Send the offset
}
axis[Motor].HBXPosn = axis[Motor].HBXTarget;
axis[Motor].HBXMotorControl &= ~MoveHBX; // Clear the flag
}
axis[Motor].HBXMotorStatus |= MOVESTEP; // Set stepping mode
axis[Motor].HBXMotorStatus &= ~MOVELOW; // and speed
axis[Motor].HBXMotorStatus &= ~MOVEAXIS; // Clear the motor moving flag
axis[Motor].ETXMotorState = ETXCheckStartup;
axis[Motor].HBXTargetSpeed = axis[Motor].DEGREERATE1 >> 3; // For any subsequent move
axis[Motor].HBXSpeed = 0;
break;
default:
break;
}
}
// Motor functions
bool HBXGetStatus(unsigned char Motor) {
axis[Motor].HBXP4 = 0xFF; // Preset error
if (!HBXSendCommand(GetStatus, Motor)) {
return(false);
}
HBXGet3Bytes(Motor);
if (axis[Motor].HBXP4 == 0) { // If no error, update position
P1 = (axis[Motor].HBXP1 << 8);
P1 |= axis[Motor].HBXP2; // Convert to 16bits
if (axis[Motor].HBXP1 & 0x80)
P1 |= 0xffff0000; // Sign extend HBXP1 for 2s complement
axis[Motor].HBXPosn += P1;
axis[Motor].HBXPosn &= 0x00FFFFFF;
return(true);
}
else return(false);
}
bool HBXGet2Status(void) {
int i;
do {
i = 0;
if (HBXGetStatus(AzMotor))
i += 1;
if (HBXGetStatus(AltMotor))
i += 1;
} while (i < 2);
return(true);
}
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)
do {
P1 = 0;
if (HBXSendCommand(GetLEDI, AzMotor))
axis[AzMotor].HBXLEDI = HBXGetByte(AzMotor);
if ((axis[AzMotor].HBXLEDI != 0) && (axis[AzMotor].HBXLEDI != 0xFF))
P1 += 1;
if (HBXSendCommand(GetLEDI, AltMotor))
axis[AltMotor].HBXLEDI = HBXGetByte(AltMotor);
if ((axis[AltMotor].HBXLEDI != 0) && (axis[AltMotor].HBXLEDI != 0xFF))
P1 += 1;
TimerDelaymS(MOTORDETECT); // Wait .5s between loops
} while (P1 < 2);
}
void AzInitialise(void) {
// ETX
axis[AzMotor].HBXP1 = 0x00;
axis[AzMotor].HBXP2 = 0x00;
axis[AzMotor].HBXP3 = 0x00;
axis[AzMotor].HBXP4 = 0x00;
axis[AzMotor].HBXPosn = ETX_CENTRE;
axis[AzMotor].HBXTarget = axis[AzMotor].HBXPosn;
axis[AzMotor].HBXDirSpeed = 0x000;
axis[AzMotor].HBXMotorStatus = MOVESTEP;
axis[AzMotor].HBX_bVALUE = EQG_RAbVALUE;
axis[AzMotor].SIDEREALRATE = AzSIDEREALRATE;
axis[AzMotor].SOLARRATE = AzSOLARRATE;
axis[AzMotor].LUNARRATE = AzLUNARRATE;
axis[AzMotor].DEGREERATE1 = AzDEGREERATE1;
axis[AzMotor].DEGREERATE2 = AzDEGREERATE2;
axis[AzMotor].SIDEREALSPEED = AzSIDEREALSPEED;
axis[AzMotor].SOLARSPEED = AzSOLARSPEED;
axis[AzMotor].LUNARSPEED = AzLUNARSPEED;
axis[AzMotor].DEGREESPEED1 = AzDEGREESPEED1;
axis[AzMotor].DEGREESPEED2 = AzDEGREESPEED2;
axis[AzMotor].STEPSPER360 = AzSTEPSPER360;
axis[AzMotor].WORM = AzWORM;
axis[AzMotor].PEC = AzPEC;
axis[AzMotor].ETXMotorState = ETXCheckStartup;
}
void AltInitialise(void) {
// ETX
axis[AltMotor].HBXP1 = 0x00;
axis[AltMotor].HBXP2 = 0x00;
axis[AltMotor].HBXP3 = 0x00;
axis[AltMotor].HBXP4 = 0x00;
axis[AltMotor].HBXPosn = ETX_CENTRE;
axis[AltMotor].HBXTarget = axis[AltMotor].HBXPosn;
axis[AltMotor].HBXDirSpeed = 0x000;
axis[AltMotor].HBXMotorStatus = MOVESTEP;
axis[AltMotor].HBX_bVALUE = EQG_DECbVALUE;
axis[AltMotor].SIDEREALRATE = AltSIDEREALRATE;
axis[AltMotor].SOLARRATE = AltSOLARRATE;
axis[AltMotor].LUNARRATE = AltLUNARRATE;
axis[AltMotor].DEGREERATE1 = AltDEGREERATE1;
axis[AltMotor].DEGREERATE2 = AltDEGREERATE2;
axis[AltMotor].SIDEREALSPEED = AltSIDEREALSPEED;
axis[AltMotor].SOLARSPEED = AltSOLARSPEED;
axis[AltMotor].LUNARSPEED = AltLUNARSPEED;
axis[AltMotor].DEGREESPEED1 = AltDEGREESPEED1;
axis[AltMotor].DEGREESPEED2 = AltDEGREESPEED2;
axis[AltMotor].STEPSPER360 = AltSTEPSPER360;
axis[AltMotor].WORM = AltWORM;
axis[AltMotor].PEC = AltPEC;
axis[AltMotor].ETXMotorState = ETXCheckStartup;
}

Wyświetl plik

@ -0,0 +1,77 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
EQG Protocol function definitions
=================================
*********************************************************/
#ifndef HBXComms
#define HBXComms
// Pin definitions for HBX interface
// =================================
#define HDA1 8 // Pin2, 4, 6 on HBX interface
#define HCL1 2 // Pin3 on HBX interface
#define HDA2 10 // Not used
#define HCL2 3 // Pin5 on HBX interface
#define CR 0x0d
#define LF 0x0a
#define HBXLEN 16
#define HBXMASK HBXLEN-1
#define H2XRESETTIME 25 // Reset H2X bus
#define BITTIME 120 // H2X clock ~200uS i.e 100us Low/High
#define LOWTIME 120 // H2X clock ~200uS i.e 100us Low/High
#define DSTABLE 60 // H2X data write delay ~ 50uS
#define DGLITCH 5 // H2X data glitch sample
#define HIGHTIME 120 // H2X clock ~200uS i.e 100us Low/High
#define ETXDELAY 6.55 // H2X ETX 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
void TimerDelayuS(unsigned int);
bool HBXSendCommand(unsigned char, 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 HBXTestLoop(void);
void HBXMonitorMode(void);
bool HBXMonitorHCL(unsigned char);
bool HBXMonitorBit(unsigned char);
bool HBXMonitorByte(unsigned char);
void HBXMonitorEnd(unsigned char);
void HBXMonitorMessage(unsigned char);
void HBXSaveState(unsigned char);
void HBXPrintStatus(unsigned char);
void HBXPrintState(unsigned char);
void HDAListen(void);
void HDATalk(void);
void HCL1Listen(void);
void HCL1Talk(void);
void HCL2Listen(void);
void HCL2Talk(void);
void H2XReset(void);
bool ResetMotor(unsigned char);
long TwosComplement(long);
// Monitor
void HBXMonitorLoop(void);
// Testing
void HBXTest(void);
bool HBXGet2Status(void);
#endif

Wyświetl plik

@ -0,0 +1,243 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
HBX Comms related functions
===========================
*********************************************************/
// HBX transmission functions
// ==========================
// HBX Send a command
// ------------------
bool HBXSendCommand(unsigned char Command, unsigned char Motor) {
unsigned long i;
axis[Motor].HBXCmnd = 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) {
HDAListen(); // HDA as input
// Set clock low
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(DSTABLE); // Wait for answer
// Wait for data low by MC, or timeout
H2XStart = micros(); // Get the start microseconds
do { // Wait for MC to answer with HDA1 = 0
H2XTimer = micros() - H2XStart;
} while ((digitalRead(HDA1) == 1) && (H2XTimer < (BITTIME << 3)));
TimerDelayuS(DGLITCH); // Just in case of data line glitch
// Check if (data low transition) or ( MC timeout)
if ((digitalRead(HDA1) == 1) || (H2XTimer >= (BITTIME << 3))) {
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
return(false); // Error Exit if no response from Motor
}
// Set clock high if data low transition (i.e. MC acknowledged clock)
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(DSTABLE);
// Wait for data line release by MC, or timeout
H2XStart = micros(); // Get the start microseconds
do { // Wait for MC to answer
H2XTimer = micros() - H2XStart;
} while ((digitalRead(HDA1) == 0) && (H2XTimer < (BITTIME << 3)));
TimerDelayuS(BITTIME);
// Check timeout for data line released
if (H2XTimer >= 8*BITTIME) {
return(false); // Error Exit if no response from Motor
}
return(true); // Success
}
// HBX Send a single byte
// ----------------------
void HBXSendByte(unsigned char databyte, unsigned char Motor) {
unsigned char b, mask;
HDATalk(); // HDA as output
axis[Motor].HBXBitCount = 8; // 8bits to go
mask = 0x80; // MSB first
// Clock was set high before entry
TimerDelayuS(HIGHTIME);
do {
axis[Motor].HBXBitCount -= 1;
// Set data bit
if (databyte & mask) digitalWrite(HDA1, HIGH);
else digitalWrite(HDA1, LOW);
TimerDelayuS(DSTABLE); // Let data stabilise
mask = mask >> 1; // Next data bit
// Set clock low
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(LOWTIME);
if (!(axis[Motor].HBXBitCount)) { // Last bit -> force float on data
digitalWrite(HDA1, LOW);
HDAListen();
}
// Set clock high
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(HIGHTIME-DSTABLE); // Data is written DSTABLE before clock low
// for 8 bits
} while (axis[Motor].HBXBitCount);
TimerDelayuS(DSTABLE); // Last high clock
}
// 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) {
unsigned long i;
unsigned char b;
HDAListen(); // HDA as input
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(DSTABLE);
// 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(LOWTIME-DSTABLE); // Wait for low time
// Set clock high
if (Motor == MotorAz) digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(HIGHTIME);
}
// Return data byte
axis[Motor].HBXCount = 1;
return (axis[Motor].HBXData);
}
// HBX Get the status bytes (25 bits)
// ----------------------------------
void HBXGet3Bytes(unsigned char Motor) {
unsigned char b;
axis[Motor].HBXP1 = HBXGetByte(Motor);
TimerDelayuS(HIGHTIME);
axis[Motor].HBXP2 = HBXGetByte(Motor);
TimerDelayuS(HIGHTIME);
axis[Motor].HBXP3 = HBXGetByte(Motor);
TimerDelayuS(HIGHTIME);
axis[Motor].HBXP4 = 0;
// Read 'byte4' = error bit
// ------------------------
if (Motor == MotorAz) digitalWrite(HCL1, LOW);
else digitalWrite(HCL2, LOW);
TimerDelayuS(DSTABLE);
axis[Motor].HBXP4 |= digitalRead(HDA1); // Read the error bit
TimerDelayuS(LOWTIME-DSTABLE);
if (Motor == MotorAz)digitalWrite(HCL1, HIGH);
else digitalWrite(HCL2, HIGH);
TimerDelayuS(HIGHTIME);
axis[Motor].HBXCount = 4;
}
// H2X Low level Functions
// -----------------------
void HDAListen() {
pinMode(HDA1, H2X_INPUT);
// digitalWrite(HDA1, HIGH);
}
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 H2XReset() {
HCL1Talk();
HCL2Talk();
HDATalk();
digitalWrite(HDA1, LOW);
TimerDelayuS(H2XRESETTIME);
digitalWrite(HDA1, HIGH);
TimerDelayuS(H2XRESETTIME);
HDAListen();
}
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,242 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
Utility functions to monitor HBX comms
======================================
ToDo:
Change to H2XISR for interrupt driven receive
*********************************************************/
void HBXMonitorLoop(void){
int Messages;
PreviousTime = millis();
Serial.println("ETX-Monitor");
// H2XReset();
axis[AzMotor].PrintStatus0 = 1; // Enable print of status = no change
axis[AltMotor].PrintStatus0 = 1; // Enable print of status = no change
HBXMonitorMode();
do {
Messages = 0;
if (HBXMonitorHCL(CLOCKTIMEOUT)) {
if (DetectedClock) {
HBXMonitorMessage(DetectedClock); // Wait for low clock and print data
axis[DetectedClock].TimeDelta = millis(); // - PreviousTime;
Messages += 1;
}
}
if (HBXMonitorHCL(CLOCKTIMEOUT)) { // Better read Alt
if (DetectedClock) {
HBXMonitorMessage(DetectedClock); // Alt may follow immediately
axis[DetectedClock].TimeDelta = millis(); // - PreviousTime;
Messages += 1;
}
}
if (Messages) {
switch(Messages) {
case 1:
HBXPrintState(DetectedClock);
break;
case 2:
if (DetectedClock == MotorAz) {
HBXPrintState(MotorAlt);
HBXPrintState(MotorAz);
}
else {
HBXPrintState(MotorAz);
HBXPrintState(MotorAlt);
}
break;
default:
break;
}
}
} while (digitalRead(MONITORHBX) == 0); // Check if jumper installed
}
void HBXMonitorMode(void) {
HDAListen(); // HDA as input
HCL1Listen(); // HCL as input
HCL2Listen();
TimerDelaymS(STARTTIME);
}
bool HBXMonitorHCL(unsigned char Timeout) {
int j;
DetectedClock = 0;
j = Timeout;
while (!digitalRead(HDA1)); // Wait for data high
while (DetectedClock == 0) { // Wait for a low on either clock
if (digitalRead(HCL1) == 0) {
TimerDelayuS(3); // Re-read in case of glitches
if (digitalRead(HCL1) == 0) DetectedClock = MotorAz;
if (digitalRead(HCL2) == 0) { // Fail if both low
DetectedClock = 0;
return (false);
}
}
else if (digitalRead(HCL2) == 0) {
TimerDelayuS(3); // Re-read in case of glitches
if (digitalRead(HCL2) == 0) DetectedClock = MotorAlt;
if (digitalRead(HCL1) == 0) { // Fail if both low
DetectedClock = 0;
return (false);
}
}
// j -= 1;
}
// if (j) {
while (digitalRead(HDA1)); // Wait for data low
while (digitalRead(HDA1)); // Wait for data low again
if (DetectedClock == MotorAz) { // Check clock is still low
if (digitalRead(HCL1)) return (false);
}
else if (digitalRead(HCL2)) return (false);
if (DetectedClock == MotorAz) {
while (!digitalRead(HCL1)); // Wait for clock high
}
else while (!digitalRead(HCL2));
return (true);
// }
// return (false); // Timeout
}
void HBXMonitorEnd(unsigned char Motor) {
if (Motor == MotorAz) while (!digitalRead(HCL1)); // Wait for clock high
else while (!digitalRead(HCL2));
}
bool HBXMonitorBit(unsigned char Motor) {
// Serial.write('!');
axis[Motor].HBXData = 0;
if (Motor == MotorAz) while (!digitalRead(HCL1)); // Wait for clock high
else while (!digitalRead(HCL2));
if (Motor == MotorAz) while (digitalRead(HCL1)); // Wait for clock low
else while (digitalRead(HCL2));
if (digitalRead(HDA1)) axis[Motor].HBXData |= 0x01; // Read the bit
return(true);
}
bool HBXMonitorByte(unsigned char Motor) {
// Serial.write('>');
axis[Motor].HBXBitCount = 8;
axis[Motor].HBXData = 0;
while (axis[Motor].HBXBitCount) {
axis[Motor].HBXData = axis[Motor].HBXData << 1; // Shift previous bit
axis[Motor].HBXBitCount--; // Need eight bits
if (Motor == MotorAz) while (!digitalRead(HCL1)); // Wait for clock high
else while (!digitalRead(HCL2));
if (Motor == MotorAz) while (digitalRead(HCL1)); // Wait for clock low
else while (digitalRead(HCL2));
if (digitalRead(HDA1)) axis[Motor].HBXData |= 0x01; // Read next bit
}
return(true);
}
void HBXMonitorMessage(unsigned char Motor) {
// Serial.write('<');
if (HBXMonitorByte(Motor))
axis[Motor].HBXCmnd = axis[Motor].HBXData;
switch (axis[Motor].HBXCmnd) {
case GetStatus: // Four bytes of data
axis[Motor].HBXCount = 4;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP1 = axis[Motor].HBXData;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP2 = axis[Motor].HBXData;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP3 = axis[Motor].HBXData;
if (HBXMonitorBit(Motor)) axis[Motor].HBXP4 = axis[Motor].HBXData;
break;
case RotateSlow: // Three bytes of data
case RotateFast:
axis[Motor].HBXCount = 3;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP1 = axis[Motor].HBXData;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP2 = axis[Motor].HBXData;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP3 = axis[Motor].HBXData;
break;
case SetOffset: // Two bytes of data
axis[Motor].HBXCount = 2;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP1 = axis[Motor].HBXData;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP2 = axis[Motor].HBXData;
break;
case SetLEDI: // One byte of data
case GetLEDI:
case GetMotorType:
axis[Motor].HBXCount = 1;
if (HBXMonitorByte(Motor)) axis[Motor].HBXP1 = axis[Motor].HBXData;
break;
case CalibrateLED: // No data
case Stop:
case SlewReverse:
case SlewForward:
case ResetH2X:
axis[Motor].HBXCount = 0;
break;
default:
break;
}
if (Motor == MotorAz) while (!digitalRead(HCL1)); // Wait for clock high
else while (!digitalRead(HCL2));
}
void HBXPrintState(unsigned char Motor) {
if (axis[Motor].HBXCmnd != GetStatus) { // Handle all other commands
Serial.print(Motor);
Serial.write(',');
Serial.print(axis[Motor].TimeDelta);
Serial.write(',');
Serial.print(axis[Motor].HBXCmnd, HEX);
if (axis[Motor].HBXCount) {
Serial.write(',');
Serial.print(axis[Motor].HBXP1);
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.write(',');
Serial.print(axis[Motor].HBXP2);
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.write(',');
Serial.print(axis[Motor].HBXP3);
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.write(',');
Serial.print(axis[Motor].HBXP4, HEX);
}
}
// Handle report status - exclude all 0 - ie nothing happened
else if (axis[Motor].HBXP1 | axis[Motor].HBXP2 | axis[Motor].HBXP3 | axis[Motor].HBXP4 | axis[Motor].PrintStatus0) {
Serial.print(Motor);
Serial.write(',');
Serial.print(axis[Motor].TimeDelta);
Serial.write(',');
Serial.print(axis[Motor].HBXCmnd);
Serial.write(',');
Serial.print((axis[Motor].HBXP1<<8) + axis[Motor].HBXP2);
Serial.write(',');
Serial.print(axis[Motor].HBXP3);
Serial.write(',');
Serial.print(axis[Motor].HBXP4, HEX);
}
Serial.println("");
}

Wyświetl plik

@ -0,0 +1,439 @@
/*
* Copyright 2017, 2018 John Archbold
*/
/********************************************************
Test HBX communications
=======================
*********************************************************/
void HBXTestLoop(void) {
TestCount = 0;
while (digitalRead(TESTHBX) == 0) {
Serial.println("Test HBX commands to ETX");
HBXTest();
TestCount += 1;
TestLoopTime = millis();
// Read motor status until jumper removed
while((millis() - TestLoopTime) < 5000) { // 5s between tests
HBXGet2Status();
}
}
}
void HBXTest(void)
{
int i;
// Initialize HBX communications as outputs
// It will use I2C-like communications
Serial.println("**********************************************");
Serial.print("Test Number - ");
Serial.println(TestCount);
Serial.println("**********************************************");
//do {
digitalWrite(FROMHBX, HIGH);
Serial1.println("**********************************************");
// TimerDelaymS(100);
Serial1.print("Test Number - ");
// TimerDelaymS(100);
Serial1.println(TestCount++);
digitalWrite(FROMHBX, LOW);
//} while(1);
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) {
Serial.println("Test - HBX Initialization");
axis[AzMotor].HBXPosn = ETX_CENTRE;
axis[AzMotor].HBXTarget = axis[AzMotor].HBXPosn;
axis[AzMotor].HBXDirSpeed = 0x000;
axis[AzMotor].HBXSpeed = 0x000000;
axis[AzMotor].HBXMotorStatus = MOVESTEP;
axis[AltMotor].HBXPosn = ETX_CENTRE;
axis[AltMotor].HBXTarget = axis[AltMotor].HBXPosn;
axis[AltMotor].HBXDirSpeed = 0x000;
axis[AltMotor].HBXSpeed = 0x000000;
axis[AltMotor].HBXMotorStatus = MOVESTEP;
// Reset the motors (RA and DEC)
Serial.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)
Serial.println("Test - Stop motors");
HBXStop2Motors();
// Read status
Serial.println("Test - Read Status");
HBXGet2Status(); // Check and read both motor states
if (!check_eeprom_crc() || !EEPROM.read(EEPROMAzLEDI) || !EEPROM.read(EEPROMAltLEDI)) {
// Calibrate Az, Alt Motor Encoder LED currents
Serial.println("Test - Calibrate RA, DEC Motor Encoder LED currents");
if (HBXSendCommand(CalibrateLED, AzMotor));
TimerDelaymS(2500);
HBXPrintStatus(AzMotor);
if (HBXSendCommand(CalibrateLED, AltMotor))
TimerDelaymS(2500);
HBXPrintStatus(AltMotor);
if (HBXSendCommand(GetLEDI, AzMotor))
axis[AzMotor].HBXLEDI = HBXGetByte(AzMotor);
EEPROM.write(EEPROMAzLEDI, axis[AzMotor].HBXLEDI);
set_eeprom_crc();
axis[AzMotor].HBXP1 = axis[AzMotor].HBXLEDI;
HBXPrintStatus(AzMotor);
if (HBXSendCommand(GetLEDI, AltMotor))
axis[AltMotor].HBXLEDI = HBXGetByte(AltMotor);
EEPROM.write(EEPROMAltLEDI, axis[AltMotor].HBXLEDI);
set_eeprom_crc();
axis[AltMotor].HBXP1 = axis[AltMotor].HBXLEDI;
HBXPrintStatus(AltMotor);
}
Serial.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);
}
axis[AzMotor].HBXLEDI = EEPROM.read(EEPROMAzLEDI);
axis[AltMotor].HBXLEDI = EEPROM.read(EEPROMAltLEDI);
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
Serial.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);
//}
Serial.println("Test - Stop motors");
HBXStop2Motors();
// First Read, clear counters
Serial.println("Test - Read Both Motor States");
HBXGet2Status();
Serial.println("Test - Begin motor move tests");
//}
// Test different motor speeds
Serial.println("Test - Motor Speed Tests");
Serial.println("========================");
Serial.println("Test - SIDEREAL");
axis[AzMotor].HBXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].HBXMotorStatus |= MOVEDIRN;
axis[AzMotor].HBXSpeed = AzSIDEREALRATE; // Sidereal
axis[AltMotor].HBXSpeed = AltSIDEREALRATE;
HBXPrintPosn(5, 1000); // Show location each second
Serial.println("Test - SIDEREAL - Stop motors");
HBXStop2Motors();
Serial.println("Test - OneDegree/sec forward");
axis[AzMotor].HBXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].HBXMotorStatus |= MOVEDIRN;
axis[AzMotor].HBXSpeed = AzDEGREERATE1; // One degree/sec
axis[AltMotor].HBXSpeed = AltDEGREERATE1; // One degree/sec
HBXPrintPosn(5, 500); // Show location each tenth of a second
Serial.println("Test - OneDegree/sec forward - Stop motors");
HBXStop2Motors();
Serial.println("Test - OneDegree/sec reverse");
axis[AzMotor].HBXMotorStatus &= ~MOVEDIRN; // Reverse
axis[AltMotor].HBXMotorStatus &= ~MOVEDIRN;
axis[AzMotor].HBXSpeed = AzDEGREERATE1; // One degree/sec
axis[AltMotor].HBXSpeed = AltDEGREERATE1; // One degree/sec
HBXPrintPosn(5, 500); // Show location each each tenth of a second
Serial.println("Test - OneDegree/sec reverse - Stop motors");
HBXStop2Motors();
Serial.println("Test - TwoDegrees/sec forward");
axis[AzMotor].HBXMotorStatus |= MOVEDIRN; // Forward
axis[AltMotor].HBXMotorStatus |= MOVEDIRN;
axis[AzMotor].HBXSpeed = AzDEGREERATE1*2; // Two degrees/sec
axis[AltMotor].HBXSpeed = AltDEGREERATE1*2; // Two degrees/sec
HBXPrintPosn(5, 1000); // Show location each tenth of a second
Serial.println("Test - TwoDegrees/sec forward - Stop motors");
HBXStop2Motors();
Serial.println("Test - TwoDegrees/sec reverse");
axis[AzMotor].HBXMotorStatus &= ~MOVEDIRN; // Reverse
axis[AltMotor].HBXMotorStatus &= ~MOVEDIRN;
axis[AzMotor].HBXSpeed = AzDEGREERATE1*2; // Two degrees/sec
axis[AltMotor].HBXSpeed = AltDEGREERATE1*2; // Two degrees/sec
HBXPrintPosn(5, 1000); // Show location each each tenth of a second
Serial.println("Test - TwoDegrees/sec reverse - Stop motors");
HBXStop2Motors();
// Read status
Serial.println("Test - Read Status");
HBXGet2Status();
// Stop the motors (Az and Alt)
Serial.println("Test - Stop motors");
HBXStop2Motors();
}
void HBXPrintPosn(unsigned int count, unsigned int duration) {
int j = 0;
axis[AzMotor].HBXPosn = ETX_CENTRE; // Reset position
axis[AltMotor].HBXPosn = ETX_CENTRE;
axis[AzMotor].HBXDelta = 0;
axis[AltMotor].HBXDelta = 0;
PreviousTime = millis();
HBXStart2Motors(); // Start the motors
do {
ETXState(AzMotor); // Check the Az motor state
ETXState(AltMotor); // Check the Alt motor state
SendPosn(duration); // Duration is delay between reads
j += 1;
} while(j < count);
}
void SendPosn(unsigned int duration) {
// Serial.println(" SendPosn");
while ((millis() - PreviousTime) < duration) ; // 1/10 second
Serial.print(millis() - PreviousTime);
Serial.print(" - ");
PreviousTime = millis();
HBXGetStatus(AzMotor);
axis[AzMotor].HBXDelta = axis[AzMotor].HBXP1 * 256 + axis[AzMotor].HBXP2;
HBXGetStatus(AltMotor);
axis[AltMotor].HBXDelta = axis[AltMotor].HBXP1 * 256 + axis[AltMotor].HBXP2;
Serial.print("Az = ");
Serial.print(axis[AzMotor].HBXPosn);
Serial.print(" : ");
Serial.print(axis[AzMotor].HBXDelta);
Serial.print(", Alt = ");
Serial.print(axis[AltMotor].HBXPosn);
Serial.print(" : ");
Serial.println(axis[AltMotor].HBXDelta);
}
void HBXPrintStatus(unsigned char Motor) {
axis[Motor].HBXCount = 0;
if ((axis[Motor].HBXCmnd != GetStatus) || (axis[Motor].HBXP1 | axis[Motor].HBXP2 | axis[Motor].HBXP3 | axis[Motor].HBXP4) || axis[Motor].PrintStatus0 ) {
Serial.print("Motor: ");
Serial.print(Motor);
Serial.print(", Cmnd: ");
Serial.print(axis[Motor].HBXCmnd, HEX);
Serial.print(" - ");
switch (axis[Motor].HBXCmnd) {
case RotateSlow:
Serial.print("RotateSlow ");
axis[Motor].HBXCount = 3;
break;
case RotateFast:
Serial.print("RotateFast ");
axis[Motor].HBXCount = 3;
break;
case SetOffset:
Serial.print("SetOffset ");
axis[Motor].HBXCount = 4;
break;
case SetLEDI:
Serial.print("SetLEDI ");
axis[Motor].HBXCount = 1;
break;
case CalibrateLED:
Serial.print("CalibrateLED ");
break;
case Stop:
Serial.print("Stop ");
break;
case SlewReverse:
Serial.print("SlewReverse ");
break;
case SlewForward:
Serial.print("SlewForward ");
break;
case GetStatus:
Serial.print("GetStatus ");
axis[Motor].HBXCount = 4;
break;
case GetLEDI:
Serial.print("GetLEDI ");
axis[Motor].HBXCount = 1;
break;
case GetMotorType:
Serial.print("GetMotorType ");
axis[Motor].HBXP1 = axis[Motor].MotorType;
axis[Motor].HBXCount = 1;
break;
case ResetH2X:
Serial.print("ResetH2X ");
break;
default:
Serial.print("UNKNOWN ");
break;
}
if (axis[Motor].HBXCount) {
Serial.print(", Data: ");
Serial.print(axis[Motor].HBXP1, HEX);
if (axis[Motor].HBXCount > 1) Serial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.print(axis[Motor].HBXP2, HEX);
if (axis[Motor].HBXCount > 1) Serial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.print(axis[Motor].HBXP3, HEX);
if (axis[Motor].HBXCount > 1) Serial.print(", ");
axis[Motor].HBXCount -= 1;
}
if (axis[Motor].HBXCount) {
Serial.print(axis[Motor].HBXP4, HEX);
axis[Motor].HBXCount -= 1;
}
Serial.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].HBXMotorStatus |= MOVEAXIS;
ETXState(AzMotor);
axis[AltMotor].ETXMotorState = ETXCheckStartup;
axis[AltMotor].HBXMotorStatus |= MOVEAXIS;
ETXState(AltMotor);
return(true);
}
void HBXPrintPosn(unsigned char Motor) {
if (Motor == MotorAz) {
digitalWrite(FROMHBX, HIGH); // Set Indicator LED
Serial.println("");
Serial.print("Time: ");
Serial.print(millis());
// Serial.print(StatusTimer - StatusTime);
// StatusTime = StatusTimer;
/* Serial.print(" AzRaw: ");
puthexb(axis[AzMotor].HBXP1);
putbyte(',');
puthexb(axis[AzMotor].HBXP2);
putbyte(',');
puthexb(axis[AzMotor].HBXP3);
putbyte(',');
puthexb(axis[AzMotor].HBXP4);
*/
Serial.print(" AzPosn: ");
puthexl(axis[AzMotor].HBXPosn);
putbyte(',');
puthexl(axis[AzMotor].HBXTarget);
putbyte(',');
puthexl(axis[AzMotor].HBXSlowDown);
Serial.print(" AzSpeed: ");
puthexl(axis[AzMotor].HBXSpeed);
putbyte(',');
puthexl(axis[AzMotor].HBXTargetSpeed);
putbyte('-');
puthexw(axis[AzMotor].HBXMotorStatus);
putbyte(',');
puthexw(axis[AzMotor].HBXMotorControl);
}
else {
/*
* Serial.print(" AltRaw: ");
puthexb(axis[AltMotor].HBXP1);
putbyte(',');
puthexb(axis[AltMotor].HBXP2);
putbyte(',');
puthexb(axis[AltMotor].HBXP3);
putbyte(',');
puthexb(axis[AltMotor].HBXP4);
*/
Serial.print(" AltPosn: ");
puthexl(axis[AltMotor].HBXPosn);
putbyte(',');
puthexl(axis[AltMotor].HBXTarget);
putbyte(',');
puthexl(axis[AltMotor].HBXSlowDown);
Serial.print(" AltSpeed: ");
puthexl(axis[AltMotor].HBXSpeed);
putbyte(',');
puthexl(axis[AltMotor].HBXTargetSpeed);
putbyte('-');
puthexw(axis[AltMotor].HBXMotorStatus);
putbyte(',');
puthexw(axis[AltMotor].HBXMotorControl);
Serial.println("");
}
digitalWrite(FROMHBX, LOW); // Clear Indicator LED
}