-
Notifications
You must be signed in to change notification settings - Fork 172
/
Globals.h
478 lines (425 loc) · 23.9 KB
/
Globals.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
// -----------------------------------------------------------------------------------
// Global variables
#pragma once
// Time keeping --------------------------------------------------------------------------------------------------------------------
long siderealTimer = 0; // counter to issue steps during tracking
long pecSiderealTimer = 0; // time since worm wheel zero index for PEC
long guideSiderealTimer = 0; // counter to issue steps during guiding
bool dateWasSet = false; // keep track of date/time validity
bool timeWasSet = false;
double UT1 = 0.0; // the current universal time
double UT1_start = 0.0; // the start of UT1
double JD = 0.0; // and date, used for computing LST
double LMT = 0.0;
double timeZone = 0.0;
long lst_start = 0; // marks the start lst when UT1 is set
volatile long lst = 0; // local (apparent) sidereal time in 0.01 second ticks,
// takes 249 days to roll over.
// 1.00273 wall clock seconds per sidereal second
const long masterSiderealInterval = 15956313L;
long siderealInterval = masterSiderealInterval;
// default = 15956313 ticks per sidereal second, where a tick
// is 1/16 uS this is stored in EEPROM which is updated/adjusted
// with the ":T+#" and ":T-#" commands a higher number here means
// a longer count which slows down the sidereal clock
const double HzCf = 16000000.0/60.0; // conversion factor to go to/from Hz for sidereal interval
volatile long siderealRate; // based on the siderealInterval, time between steps sidereal tracking
volatile long backlashTakeupRate; // backlash takeup rate
unsigned long last_loop_micros = 0; // workload monitoring
long this_loop_time = 0;
long loop_time = 0;
long worst_loop_time = 0;
long average_loop_time = 0;
// PPS (GPS) -----------------------------------------------------------------------------------------------------------------------
volatile unsigned long ppsLastMicroS = 1000000UL;
volatile unsigned long ppsAvgMicroS = 1000000UL;
volatile double ppsRateRatio = 1.0;
volatile double ppsLastRateRatio = 1.0;
volatile bool ppsSynced = false;
// Tracking and rate control -------------------------------------------------------------------------------------------------------
#if MOUNT_TYPE != ALTAZM
enum RateCompensation {RC_NONE, RC_REFR_RA, RC_REFR_BOTH, RC_FULL_RA, RC_FULL_BOTH};
#if TRACK_REFRACTION_RATE_DEFAULT == ON
RateCompensation rateCompensation = RC_REFR_RA;
#else
RateCompensation rateCompensation = RC_NONE;
#endif
#else
enum RateCompensation {RC_NONE};
RateCompensation rateCompensation = RC_NONE;
#endif
double slewSpeed = 0;
volatile long timerRateAxis1 = 0;
volatile long timerRateBacklashAxis1 = 0;
volatile bool inbacklashAxis1 = false;
bool haltAxis1 = false;
bool faultAxis1 = false;
volatile long timerRateAxis2 = 0;
volatile long timerRateBacklashAxis2 = 0;
volatile bool inbacklashAxis2 = false;
bool haltAxis2 = false;
bool faultAxis2 = false;
#if AXIS1_DRIVER_MODEL == TMC_SPI
#define AXIS1_DRIVER_SWITCH_RATE timerRateBacklashAxis1
#else
#define AXIS1_DRIVER_SWITCH_RATE 80*16L
#endif
#if AXIS2_DRIVER_MODEL == TMC_SPI
#define AXIS2_DRIVER_SWITCH_RATE timerRateBacklashAxis2
#else
#define AXIS2_DRIVER_SWITCH_RATE 80*16L
#endif
#pragma pack(1)
typedef struct AxisSettings {
double stepsPerMeasure; // degrees for axis1-3 or microns for axis4-5
int16_t microsteps;
int16_t IRUN;
int8_t reverse;
int16_t min;
int16_t max;
} axisSettings;
#pragma pack()
volatile axisSettings axis1Settings = {AXIS1_STEPS_PER_DEGREE, AXIS1_DRIVER_MICROSTEPS, AXIS1_DRIVER_IRUN, AXIS1_DRIVER_REVERSE, AXIS1_LIMIT_MIN, AXIS1_LIMIT_MAX};
volatile axisSettings axis2Settings = {AXIS2_STEPS_PER_DEGREE, AXIS2_DRIVER_MICROSTEPS, AXIS2_DRIVER_IRUN, AXIS2_DRIVER_REVERSE, AXIS2_LIMIT_MIN, AXIS2_LIMIT_MAX};
volatile axisSettings axis3Settings = {AXIS3_STEPS_PER_DEGREE, AXIS3_DRIVER_MICROSTEPS, AXIS3_DRIVER_IRUN, AXIS3_DRIVER_REVERSE, AXIS3_LIMIT_MIN, AXIS3_LIMIT_MAX};
volatile axisSettings axis4Settings = {AXIS4_STEPS_PER_MICRON, AXIS4_DRIVER_MICROSTEPS, AXIS4_DRIVER_IRUN, AXIS4_DRIVER_REVERSE, AXIS4_LIMIT_MIN, AXIS4_LIMIT_MAX};
volatile axisSettings axis5Settings = {AXIS5_STEPS_PER_MICRON, AXIS5_DRIVER_MICROSTEPS, AXIS5_DRIVER_IRUN, AXIS5_DRIVER_REVERSE, AXIS5_LIMIT_MIN, AXIS5_LIMIT_MAX};
typedef struct AxisSettingsEx {
int16_t IHOLD;
int16_t IGOTO;
} axisSettingsEx;
axisSettingsEx axis1SettingsEx = {AXIS1_DRIVER_IHOLD, AXIS1_DRIVER_IGOTO};
axisSettingsEx axis2SettingsEx = {AXIS2_DRIVER_IHOLD, AXIS2_DRIVER_IGOTO};
axisSettingsEx axis3SettingsEx = {AXIS3_DRIVER_IHOLD, OFF};
axisSettingsEx axis4SettingsEx = {AXIS4_DRIVER_IHOLD, OFF};
axisSettingsEx axis5SettingsEx = {AXIS5_DRIVER_IHOLD, OFF};
unsigned long axis1StepsGoto = 1;
unsigned long axis2StepsGoto = 1;
#define stepsPerSecondAxis1 (axis1Settings.stepsPerMeasure/240.0)
#define arcSecPerStepAxis1 (3600.0/axis1Settings.stepsPerMeasure)
#define stepsPerSecondAxis2 (axis2Settings.stepsPerMeasure/240.0)
#define arcSecPerStepAxis2 (3600.0/axis2Settings.stepsPerMeasure)
#define DefaultTrackingRate 1
volatile double trackingTimerRateAxis1 = DefaultTrackingRate;
volatile double trackingTimerRateAxis2 = DefaultTrackingRate;
volatile double timerRateRatio = AXIS1_STEPS_PER_DEGREE/AXIS2_STEPS_PER_DEGREE;
volatile bool useTimerRateRatio;
long stepsPerWormRotationAxis1;
long secondsPerWormRotationAxis1;
long maxRate;
#define maxRateBaseDesired ((1000000.0/(SLEW_RATE_BASE_DESIRED))/axis1Settings.stepsPerMeasure)
double maxRateBaseActual;
volatile double stepsForRateChangeAxis1;
volatile double stepsForRateChangeAxis2;
// Basic stepper driver mode setup -------------------------------------------------------------------------------------------------
#if AXIS1_DRIVER_MODEL != OFF
// Holds translated code for driver microstep setting
volatile uint8_t _axis1_code;
#define AXIS1_DRIVER_CODE _axis1_code
#if AXIS1_DRIVER_MICROSTEPS_GOTO != OFF
volatile uint8_t _axis1_code_goto;
#define AXIS1_DRIVER_CODE_GOTO _axis1_code_goto
#endif
#endif
#if AXIS2_DRIVER_MODEL != OFF
volatile uint8_t _axis2_code;
#define AXIS2_DRIVER_CODE _axis2_code
#if AXIS2_DRIVER_MICROSTEPS_GOTO != OFF
volatile uint8_t _axis2_code_goto;
#define AXIS2_DRIVER_CODE_GOTO _axis2_code_goto
#endif
#endif
#if AXIS3_DRIVER_MODEL != OFF
volatile uint8_t _axis3_code;
#define AXIS3_DRIVER_CODE _axis3_code
#endif
#if AXIS4_DRIVER_MODEL != OFF
volatile uint8_t _axis4_code;
#define AXIS4_DRIVER_CODE _axis4_code
#endif
#if AXIS5_DRIVER_MODEL != OFF
volatile uint8_t _axis5_code;
#define AXIS5_DRIVER_CODE _axis5_code
#endif
// Location ------------------------------------------------------------------------------------------------------------------------
double latitude = 0.0;
double latitudeAbs = 0.0;
double latitudeSign = 1.0;
double cosLat = 1.0;
double sinLat = 0.0;
double longitude = 0.0;
// Coordinates ---------------------------------------------------------------------------------------------------------------------
#ifndef TELESCOPE_COORDINATES
#define TELESCOPE_COORDINATES TOPOCENTRIC
#endif
#ifndef AXIS1_HOME_DEFAULT
#if MOUNT_TYPE == GEM
#define AXIS1_HOME_DEFAULT 90.0
#else
#define AXIS1_HOME_DEFAULT 0.0
#endif
#endif
double homePositionAxis1 = AXIS1_HOME_DEFAULT;
volatile long posAxis1 = 0; // hour angle position in steps
volatile int blAxis1 = 0; // backlash position in steps
volatile int backlashAxis1 = 0; // total backlash in steps
volatile long startAxis1 = 0; // hour angle of goto start position in steps
volatile fixed_t targetAxis1; // hour angle of goto end position in steps
double origTargetRA = 0.0; // holds the RA for gotos before possible conversion to observed place
double newTargetRA = 0.0; // holds the RA for gotos after conversion to observed place
double newTargetAzm = 0.0; // holds the altitude and azmiuth for slews
fixed_t origTargetAxis1;
double indexAxis1 = 0; // index offset corrections, simple align/sync
long indexAxis1Steps = 0;
volatile int stepAxis1=1;
fixed_t fstepAxis1; // tracking and PEC, fractional steps
#ifndef AXIS2_HOME_DEFAULT
#if MOUNT_TYPE == ALTAZM
#define AXIS2_HOME_DEFAULT 0.0
#else
#define AXIS2_HOME_DEFAULT 90.0 // always positive, sign is automatically adjusted for hemisphere
#endif
#endif
double homePositionAxis2 = AXIS2_HOME_DEFAULT;
volatile long posAxis2 = 0; // declination position in steps
volatile int blAxis2 = 0; // backlash position in steps
volatile int backlashAxis2 = 0; // total backlash in steps
volatile long startAxis2 = 0; // declination of goto start position in steps
volatile fixed_t targetAxis2; // declination of goto end position in steps
double origTargetDec = 0.0; // holds the Dec for gotos before possible conversion to observed place
double newTargetDec = 0.0; // holds the Dec for gotos after conversion to observed place
double newTargetAlt = 0.0; // holds the altitude and azmiuth for slews
fixed_t origTargetAxis2;
double indexAxis2 = 0; // index offset corrections, simple align/sync
long indexAxis2Steps = 0;
volatile int stepAxis2=1;
fixed_t fstepAxis2; // tracking and PEC, fractional steps
double currentAlt = 45.0; // the current altitude
double currentDec = 0.0; // the current declination
// Limits --------------------------------------------------------------------------------------------------------------------------
long degreesPastMeridianE = 15; // east of pier. How far past the meridian before we do a flip.
long degreesPastMeridianW = 15; // west of pier. Mount stops tracking when it hits the this limit.
int minAlt; // the min altitude, in deg, so we don't try to point too low
int maxAlt; // the max altitude, in deg, keeps telescope away from mount/tripod
// Stepper driver enable/disable and direction -------------------------------------------------------------------------------------
#define DefaultDirAxis1NCPInit 0
#define DefaultDirAxis1SCPInit 1
volatile byte dirAxis1 = 1; // stepping direction + or -
volatile byte defaultDirAxis1 = DefaultDirAxis1NCPInit;
#define DefaultDirAxis2EInit 1
#define DefaultDirAxis2WInit 0
volatile byte dirAxis2 = 1; // stepping direction + or -
volatile byte defaultDirAxis2 = DefaultDirAxis2EInit;
// Status --------------------------------------------------------------------------------------------------------------------------
// Note: the following error codes are obsolete ERR_SYNC, ERR_PARK
enum GeneralErrors {
ERR_NONE, ERR_MOTOR_FAULT, ERR_ALT_MIN, ERR_LIMIT_SENSE, ERR_DEC, ERR_AZM,
ERR_UNDER_POLE, ERR_MERIDIAN, ERR_SYNC, ERR_PARK, ERR_GOTO_SYNC, ERR_UNSPECIFIED,
ERR_ALT_MAX, ERR_WEATHER_INIT, ERR_SITE_INIT, ERR_NV_INIT};
GeneralErrors generalError = ERR_NONE;
enum CommandErrors {
CE_NONE, CE_0, CE_CMD_UNKNOWN, CE_REPLY_UNKNOWN, CE_PARAM_RANGE, CE_PARAM_FORM,
CE_ALIGN_FAIL, CE_ALIGN_NOT_ACTIVE, CE_NOT_PARKED_OR_AT_HOME, CE_PARKED,
CE_PARK_FAILED, CE_NOT_PARKED, CE_NO_PARK_POSITION_SET, CE_GOTO_FAIL, CE_LIBRARY_FULL,
CE_GOTO_ERR_BELOW_HORIZON, CE_GOTO_ERR_ABOVE_OVERHEAD, CE_SLEW_ERR_IN_STANDBY,
CE_SLEW_ERR_IN_PARK, CE_GOTO_ERR_GOTO, CE_SLEW_ERR_OUTSIDE_LIMITS, CE_SLEW_ERR_HARDWARE_FAULT,
CE_MOUNT_IN_MOTION, CE_GOTO_ERR_UNSPECIFIED, CE_NULL};
CommandErrors commandError = CE_NONE;
#if DEBUG != OFF
// command errors
#define L_CE_NONE "No Errors"
#define L_CE_0 "reply 0"
#define L_CE_CMD_UNKNOWN "command unknown"
#define L_CE_REPLY_UNKNOWN "invalid reply"
#define L_CE_PARAM_RANGE "parameter out of range"
#define L_CE_PARAM_FORM "bad parameter format"
#define L_CE_ALIGN_FAIL "align failed"
#define L_CE_ALIGN_NOT_ACTIVE "align not active"
#define L_CE_NOT_PARKED_OR_AT_HOME "not parked or at home"
#define L_CE_PARKED "already parked"
#define L_CE_PARK_FAILED "park failed"
#define L_CE_NOT_PARKED "not parked"
#define L_CE_NO_PARK_POSITION_SET "no park position set"
#define L_CE_GOTO_FAIL "goto failed"
#define L_CE_LIBRARY_FULL "library full"
#define L_CE_GOTO_ERR_BELOW_HORIZON "goto below horizon"
#define L_CE_GOTO_ERR_ABOVE_OVERHEAD "goto above overhead"
#define L_CE_SLEW_ERR_IN_STANDBY "slew in standby"
#define L_CE_SLEW_ERR_IN_PARK "slew in park"
#define L_CE_GOTO_ERR_GOTO "already in goto"
#define L_CE_SLEW_ERR_OUTSIDE_LIMITS "outside limits"
#define L_CE_SLEW_ERR_HARDWARE_FAULT "hardware fault"
#define L_CE_MOUNT_IN_MOTION "mount in motion"
#define L_CE_GOTO_ERR_UNSPECIFIED "other"
#define L_CE_UNK "unknown"
char commandErrorStr[30][25] = {
L_CE_NONE, L_CE_0, L_CE_CMD_UNKNOWN, L_CE_REPLY_UNKNOWN, L_CE_PARAM_RANGE,
L_CE_PARAM_FORM, L_CE_ALIGN_FAIL, L_CE_ALIGN_NOT_ACTIVE, L_CE_NOT_PARKED_OR_AT_HOME,
L_CE_PARKED, L_CE_PARK_FAILED, L_CE_NOT_PARKED, L_CE_NO_PARK_POSITION_SET, L_CE_GOTO_FAIL,
L_CE_LIBRARY_FULL, L_CE_GOTO_ERR_BELOW_HORIZON, L_CE_GOTO_ERR_ABOVE_OVERHEAD,
L_CE_SLEW_ERR_IN_STANDBY, L_CE_SLEW_ERR_IN_PARK, L_CE_GOTO_ERR_GOTO, L_CE_SLEW_ERR_OUTSIDE_LIMITS,
L_CE_SLEW_ERR_HARDWARE_FAULT, L_CE_MOUNT_IN_MOTION, L_CE_GOTO_ERR_UNSPECIFIED, L_CE_UNK};
#else
char commandErrorStr[0][0];
#endif
enum PrecisionMode {PM_LOW, PM_HIGH, PM_HIGHEST};
PrecisionMode precision = PM_HIGH;
// Tracking modes ------------------------------------------------------------------------------------------------------------------
#define TrackingNone 0
#define TrackingSidereal 1
#define TrackingMoveTo 2
#define StartAbortGoto 1
volatile byte trackingState = TrackingNone;
byte abortTrackingState = TrackingNone;
volatile byte lastTrackingState = TrackingNone;
int trackingSyncSeconds = 0;
byte abortGoto = 0;
volatile bool safetyLimitsOn = false;
bool axis1Enabled = false;
bool axis2Enabled = false;
bool syncToEncodersOnly = false;
enum StopSlewActions {SS_ALL_FAST, SS_LIMIT, SS_LIMIT_HARD, SS_LIMIT_AXIS1_MIN, SS_LIMIT_AXIS1_MAX, SS_LIMIT_AXIS2_MIN, SS_LIMIT_AXIS2_MAX};
// Meridian flips ------------------------------------------------------------------------------------------------------------------
#define MeridianFlipNever 0
#define MeridianFlipAlign 1
#define MeridianFlipAlways 2
#if MOUNT_TYPE == GEM
byte meridianFlip = MeridianFlipAlways;
#endif
#if MOUNT_TYPE == FORK
byte meridianFlip = MeridianFlipNever;
#endif
#if MOUNT_TYPE == ALTAZM
byte meridianFlip = MeridianFlipNever;
#endif
byte pierSideControl = PierSideNone;
int preferredPierSide = PIER_SIDE_PREFERRED_DEFAULT;
bool autoMeridianFlip = false; // auto meridian flip/continue as tracking hits AXIS1_LIMIT_MERIDIAN_W
bool pauseHome = false; // allow pause at home?
bool waitingHomeContinue = false; // set to true to stop pause
bool waitingHome = false; // true if waiting at home
// Parking -------------------------------------------------------------------------------------------------------------------------
#define PCB_BUSY -1
#define PCB_FAILURE 0
#define PCB_SUCCESS 1
#define PARK_STATUS_FIRST 0
#define NotParked 0
#define Parking 1
#define Parked 2
#define ParkFailed 3
#define ParkUnknown 4
#define PARK_STATUS_LAST 4
byte parkStatus = NotParked;
bool parkSaved = false;
// Homing --------------------------------------------------------------------------------------------------------------------------
bool atHome = true;
bool homeMount = false;
// Command processing --------------------------------------------------------------------------------------------------------------
#define BAUD 9600
// serial speed
unsigned long baudRate[10] = {115200,57600,38400,28800,19200,14400,9600,4800,2400,1200};
// Guiding and slewing -------------------------------------------------------------------------------------------------------------
#define RateToDegPerSec (1000000.0/axis1Settings.stepsPerMeasure)
#define RateToASPerSec (RateToDegPerSec*3600.0)
#define RateToXPerSec (RateToASPerSec/15.0)
double slewRateX;
double accXPerSec;
double guideRates[10]={3.75,7.5,15,30,60,120,300,720, 720, 720};
// .25X .5x 1x 2x 4x 8x 20x 48x half-MaxRate MaxRate
// 0 1 2 3 4 5 6 7 8 9
#define GuideRate1x 2
#ifndef GuideRateDefault
#define GuideRateDefault 6
#endif
#define GuideRateNone 255
int currentGuideRate = GuideRateDefault;
byte currentPulseGuideRate = GuideRate1x;
volatile byte activeGuideRate = GuideRateNone;
volatile byte guideDirAxis1 = 0;
char ST4DirAxis1 = 'b';
volatile byte guideDirAxis2 = 0;
char ST4DirAxis2 = 'b';
int spiralGuide = 0;
volatile double guideTimerRateAxis1 = 0.0;
volatile double guideTimerRateAxis2 = 0.0;
volatile double guideTimerBaseRateAxis1 = 0.0;
volatile double guideTimerBaseRateAxis2 = 0.0;
fixed_t amountGuideAxis1;
fixed_t guideAxis1;
fixed_t amountGuideAxis2;
fixed_t guideAxis2;
// PEC control ---------------------------------------------------------------------------------------------------------------------
#define PEC_STATUS_FIRST 0
#define IgnorePEC 0
#define ReadyPlayPEC 1
#define PlayPEC 2
#define ReadyRecordPEC 3
#define RecordPEC 4
#define PEC_STATUS_LAST 4
#define PECStatusString "IpPrR"
#define PECStatusStringAlt "/,~;^"
byte pecStatus = IgnorePEC;
bool pecRecorded = false;
bool pecFirstRecord = false;
long lastPecIndex = -1;
int pecBufferSize = 0;
long pecIndex = 0;
long pecIndex1 = 0;
#if PEC_SENSE == ON || PEC_SENSE == ON_PULLUP || PEC_SENSE == ON_PULLDOWN
int pecValue = PEC_SENSE_STATE;
#elif PEC_SENSE_STATE == HIGH
int pecValue = 1023;
#else
int pecValue = 0;
#endif
int pecAutoRecord = 0; // for writing to PEC table to EEPROM
long wormSensePos = 0; // in steps
bool wormSensedAgain = false; // indicates PEC index was found
bool pecBufferStart = false;
fixed_t accPecGuideHA; // for PEC, buffers steps to be recorded
volatile double pecTimerRateAxis1 = 0.0;
#if AXIS1_PEC == ON
static byte *pecBuffer;
#endif
// Misc ----------------------------------------------------------------------------------------------------------------------------
#define Rad 57.29577951
// current site index and name
byte currentSite = 0;
char siteName[16];
// status state
bool ledOn = false;
bool led2On = false;
// sound/buzzer
#if BUZZER_STATE_DEFAULT == ON
bool soundEnabled = true;
#else
bool soundEnabled = false;
#endif
volatile int buzzerDuration = 0;
// reticule control
#if LED_RETICLE >= 0
int reticuleBrightness=LED_RETICLE;
#endif
// aux pin control
#ifdef FEATURES_PRESENT
typedef struct Features {
const char* name;
const int purpose;
const int64_t temp;
const int64_t pin;
int value;
int active;
dewHeaterControl *dewHeater;
intervalometerControl *intervalometer;
} features;
features feature[8] = {
{FEATURE1_NAME,FEATURE1_PURPOSE,FEATURE1_TEMP,FEATURE1_PIN,FEATURE1_DEFAULT_VALUE,FEATURE1_ACTIVE_STATE,NULL,NULL},
{FEATURE2_NAME,FEATURE2_PURPOSE,FEATURE2_TEMP,FEATURE2_PIN,FEATURE2_DEFAULT_VALUE,FEATURE2_ACTIVE_STATE,NULL,NULL},
{FEATURE3_NAME,FEATURE3_PURPOSE,FEATURE3_TEMP,FEATURE3_PIN,FEATURE3_DEFAULT_VALUE,FEATURE3_ACTIVE_STATE,NULL,NULL},
{FEATURE4_NAME,FEATURE4_PURPOSE,FEATURE4_TEMP,FEATURE4_PIN,FEATURE4_DEFAULT_VALUE,FEATURE4_ACTIVE_STATE,NULL,NULL},
{FEATURE5_NAME,FEATURE5_PURPOSE,FEATURE5_TEMP,FEATURE5_PIN,FEATURE5_DEFAULT_VALUE,FEATURE5_ACTIVE_STATE,NULL,NULL},
{FEATURE6_NAME,FEATURE6_PURPOSE,FEATURE6_TEMP,FEATURE6_PIN,FEATURE6_DEFAULT_VALUE,FEATURE6_ACTIVE_STATE,NULL,NULL},
{FEATURE7_NAME,FEATURE7_PURPOSE,FEATURE7_TEMP,FEATURE7_PIN,FEATURE7_DEFAULT_VALUE,FEATURE7_ACTIVE_STATE,NULL,NULL},
{FEATURE8_NAME,FEATURE8_PURPOSE,FEATURE8_TEMP,FEATURE8_PIN,FEATURE8_DEFAULT_VALUE,FEATURE8_ACTIVE_STATE,NULL,NULL}
};
#endif