k3ng_rotator_controller/k3ng_rotator_controller.ino
2013-09-11 19:25:04 -04:00

6550 lines
248 KiB
C++

/* Arduino Rotator Controller "2.0 Edition"
Anthony Good
K3NG
anthony.good@gmail.com
Contributions from John Eigenbode, W3SA
w3sa@arrl.net
Contributions: AZ/EL testing and debugging, AZ/EL LCD Enhancements, original North center code, Az/El Rotator Control Connector Pins
Contributions from Jim Balls, M0CKE
makidoja@gmail.com
Contributions: Rotary Encoder Preset Support
Contributions from Gord, VO1GPK
Contribution: FEATURE_ADAFRUIT_BUTTONS code
***************************************************************************************************************
This program is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
http://creativecommons.org/licenses/by-nc-sa/3.0/
http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
***************************************************************************************************************
All copyrights are the property of their respective owners
ASCII Art Schematic
+----------------Yaesu Pin 1
|
N
D6---{1000 ohms}---P 2N2222
N or similar
|
GND
+----------------Yaesu Pin 2
|
N
D7---{1000 ohms}---P 2N2222
N or similar
|
GND
A0-------------+---------------------Yaesu Pin 4
|
[0.01uF]
|
GND
D10---{4.7K}---+---------------------Yaesu Pin 3
|
[10uF]
|
GND
Not Connected------------------------Yaesu Pin 6
GND----------------------------------Yaesu Pin 5
Alternatively Yaesu Pin 3 can be connected to Pin 6 if variable speed functionality (X commands) are not desired. This will feed +5V directly
into the speed voltage pin and set the unit for maximum speed all the time
Yaesu Azimuth Only Rotator Controller Connector Pins
6 || 5
4 3
2 1
1 - ground to rotate L
2 - ground to rotate R
3 - speed voltage (input); 4.5V = max speed
4 - analog azimuth voltage (output); 0V = full CCW, ~4.9V = full CW
5 - ground
6 - +5V or so
Yaesu Az/El Rotator Control Connector Pins
7 | | 6
3 8 1
5 4
2
1 - 2 - 4.5 VDC corresponding to 0 to 180 degrees elevation
2 - Connect to Pin 8 to rotate right (clockwise)
3 - Connect to Pin 8 to rotate Down
4 - Connect to Pin 8 to rotate left (counterclockwise)
5 - Connect to Pin 8 to rotate Up
6 - 2 - 4.5 VDC corresponding to 0 to 450 degrees rotation
7 - 13 - 6 VDC at up to 200 mA
8 - Common ground
ASCII Art Schematic
+----------------Yaesu Pin 4
|
N
D6--{1000 ohms}---P 2N2222
N or similar
|
GND
+----------------Yaesu Pin 2
|
N
D7--{1000 ohms}---P 2N2222
N or similar
|
GND
+----------------Yaesu Pin 5
|
N
D8--{1000 ohms}---P 2N2222
N or similar
|
GND
+----------------Yaesu Pin 3
|
N
D9--{1000 ohms}---P 2N2222
N or similar
|
GND
A0-----------------------------------Yaesu Pin 6
A1-----------------------------------Yaesu Pin 1
NC-----------------------------------Yaesu Pin 7
GND----------------------------------Yaesu Pin 8
Quick Start
In order to test and calibrate your unit, connect the Serial Monitor to the COM port set for 9600 and carriage return
All command letters must be uppercase.
The backslash d (\d) command toggles debug mode which will periodically display key parameters.
To test basic operation, send commands using Serial Monitor:
Rotate left(CCW): L
Rotate right(CW): R
Stop rotation: A or S commands
Read the current azimuth: C
Go to an azimuth automatically: M command (examples: M180 = go to 180 degrees, M010 = go to 10 degrees
To calibrate the unit, send the O command and rotate to 180 degrees / full CCW and send a carriage return, then
send the F command and rotate to 270 degrees / full CW and send a carriage return (assuming a 450 degrees rotation rotator).
If you are operating a 360 degree rotation rotator, for the F command rotate to 180 degrees full CW, not 270.
( CW means clockwise (or LEFT on Yaesu rotators) and CCW means counter clockwise (or RIGHT on Yaesu rotators))
To use this code with AZ/EL rotators, uncomment the FEATURE_ELEVATION_CONTROL line below
It does properly handle the 450 degree rotation capability of the Yaesu rotators.
This code has been successfully interfaced with non-Yaesu rotators. Email me if you have a rotator you would like to interface this to.
With the addition of a reasonable capacity DC power supply and two relays, this unit could entirely replace a control unit if desired.
9/12/11 W3SA JJE added code to correct elevation display which was not following A1 input (map function was not working using the variables)
Added code to keep azimuth and elevation updated if changed from the rotor control unit.
Added code to handle flipped azimuth of antenna when elevation passes 90 degrees.
Changed LCD display to display Direction, Azimuth and Elevation of antenna(s) on first line of display and actual Rotor azimuth and elevation on the second line
Then when the elevation has passed 90 degrees you would get:
NNE A 15 E 75
RTR A 195 E 115
Otherwise it would be
NNE A 15 E 75
RTR A 15 E 75
01/02/13 M0CKE added code for a cheap rotary encoder input for setting the azimuth direction, rotary encoder connected to pins 6 & 7 with the center to ground,
degrees are set by turning the encoder cw or ccw with 1 click being 1 degree if turned slowly or 1 click being 10 degree by turning quickly, this replaces the
preset pot and can be enabled by uncommenting "#define FEATURE_AZ_PRESET_ENCODER" below.
*/
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <math.h>
#include <avr/wdt.h>
#include "rotator_features.h"
#include "rotator_pins.h"
//#include "pins.h"
//#include "pins_m0upu.h"
#define CODE_VERSION "2013091101"
/* -------------------------- rotation settings ---------------------------------------*/
#define AZIMUTH_STARTING_POINT_DEFAULT 180 // the starting point in degrees of the azimuthal rotator
// (the Yaesu GS-232B Emulation Z command will override this and write the setting to eeprom)
#define AZIMUTH_ROTATION_CAPABILITY_DEFAULT 450 // the default rotation capability of the rotator in degrees
// (the Yaesu P36 and P45 commands will override this and write the setting to eeprom)
#define ELEVATION_MAXIMUM_DEGREES 180 // change this to set the maximum elevation in degrees
/* ---------------------------- object declarations ----------------------------------------------
Object declarations are required for several devices, including LCD displays, compass devices, and accelerometers
*/
/* uncomment this section for classic 4 bit interface LCD display (in addition to FEATURE_LCD_DISPLAY above) */
//#define FEATURE_LCD_DISPLAY
//#include <LiquidCrystal.h>
//LiquidCrystal lcd(lcd_4_bit_rs_pin, lcd_4_bit_enable_pin, lcd_4_bit_d4_pin, lcd_4_bit_d5_pin, lcd_4_bit_d6_pin, lcd_4_bit_d7_pin);
/* end of classic 4 bit interface LCD display section */
/* uncomment this section for Adafruit I2C LCD display */
//#define FEATURE_LCD_DISPLAY
//#define FEATURE_I2C_LCD
//#include <Adafruit_MCP23017.h>
//#include <Adafruit_RGBLCDShield.h>
//Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
//#define FEATURE_ADAFRUIT_BUTTONS // Uncomment this to use Adafruit LCD buttons for manual AZ/EL instead of normal buttons
/* end of Adafruit I2C LCD display */
/* uncomment the section for YourDuino.com I2C LCD display */
//#define FEATURE_LCD_DISPLAY
//#define FEATURE_I2C_LCD
//#define OPTION_INITIALIZE_YOURDUINO_I2C
//#define I2C_ADDR 0x20
//#define BACKLIGHT_PIN 3
//#define En_pin 2
//#define Rw_pin 1
//#define Rs_pin 0
//#define D4_pin 4
//#define D5_pin 5
//#define D6_pin 6
//#define D7_pin 7
//#define LED_OFF 1
//#define LED_ON 0
//#include <LCD.h>
//#include <LiquidCrystal_I2C.h>
//LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
/* end of of section to uncomment for YourDuino.com I2C LCD display */
/* uncomment the section for DFRobot I2C LCD display */
//#define FEATURE_LCD_DISPLAY
//#define FEATURE_I2C_LCD
//#include <LiquidCrystal_I2C.h>
//LiquidCrystal_I2C lcd(0x27,16,2);
/* end of of section to uncomment for DFRobot I2C LCD display */
//#include <HMC5883L.h> // Uncomment for experimental HMC5883L digital compass support
//HMC5883L compass; // Uncomment for HMC5883L digital compass support
//#include <Adafruit_Sensor.h> // uncomment for any Adafruit sensors/libraries
//#include <ADXL345.h> // Uncomment for elevation ADXL345 accelerometer using Love Electronics ADXL345 library
//ADXL345 accel; // Uncomment for elevation ADXL345 accelerometer support using Love Electronics ADXL345 library
//#include <Adafruit_ADXL345.h> // uncomment for elevation ADXL345 accelerometer using Adafruit ADXL345 library
//Adafruit_ADXL345 accel = Adafruit_ADXL345(12345); // Uncomment for elevation ADXL345 accelerometer support using Adafruit ADXL345 library
//#include <Adafruit_LSM303.h> // uncomment for azimuth / elevation LSM303 compass / accelerometer
//Adafruit_LSM303 lsm; // Uncomment for LSM303 support (azimuth and/or elevation) using Adafruit LSM303 library
/* ---------------------- dependency checking - don't touch this unless you know what you are doing ---------------------*/
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
#define OPTION_SERIAL1_SUPPORT
#endif
#if defined(__AVR_ATmega2560__)
#define OPTION_SERIAL2_SUPPORT
#define OPTION_SERIAL3_SUPPORT
#endif
#if (defined(FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT) || defined(FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT)) && !defined(FEATURE_HOST_REMOTE_PROTOCOL)
#define FEATURE_HOST_REMOTE_PROTOCOL
#endif
#if !defined(FEATURE_REMOTE_UNIT_SLAVE) && !defined(FEATURE_YAESU_EMULATION) && !defined(FEATURE_EASYCOM_EMULATION)
#error "You need to activate FEATURE_YAESU_EMULATION or FEATURE_YAESU_EMULATION or make this unit a remote by activating FEATURE_REMOTE_UNIT_SLAVE"
#endif
#if defined(FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT) && !defined(OPTION_SERIAL1_SUPPORT)
#error "You need hardware with Serial1 port for remote unit communications"
#undef FEATURE_HOST_REMOTE_PROTOCOL
#undef FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
#endif
#if defined(FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT) && !defined(OPTION_SERIAL1_SUPPORT)
#error "You need hardware with Serial1 port for remote unit communications"
#undef FEATURE_HOST_REMOTE_PROTOCOL
#undef FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
#endif
#if defined(FEATURE_EL_POSITION_PULSE_INPUT) && !defined(FEATURE_ELEVATION_CONTROL)
#undef FEATURE_EL_POSITION_PULSE_INPUT
#endif
#if defined(FEATURE_REMOTE_UNIT_SLAVE) && defined(FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT)
#error "You must turn off FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT if using FEATURE_REMOTE_UNIT_SLAVE"
#undef FEATURE_HOST_REMOTE_PROTOCOL
#undef FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
#endif //FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
#if defined(FEATURE_REMOTE_UNIT_SLAVE) && defined(FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT)
#error "You must turn off FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT if using FEATURE_REMOTE_UNIT_SLAVE"
#undef FEATURE_HOST_REMOTE_PROTOCOL
#undef FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
#endif
#if defined(FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT) && (defined(FEATURE_AZ_POSITION_POTENTIOMETER)||defined(FEATURE_AZ_POSITION_ROTARY_ENCODER)||defined(FEATURE_AZ_POSITION_PULSE_INPUT)||defined(FEATURE_AZ_POSITION_HMC5883L))
#error "You cannot get AZ position from remote unit and have a local azimuth sensor defined"
#endif
#if defined(FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT) && (defined(FEATURE_EL_POSITION_POTENTIOMETER)||defined(FEATURE_EL_POSITION_ROTARY_ENCODER)||defined(FEATURE_EL_POSITION_PULSE_INPUT)||defined(FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB)||defined(FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB))
#error "You cannot get EL position from remote unit and have a local elevation sensor defined"
#endif
#if (defined(FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB) && defined(FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB))
#error "You must select only one one library for the ADXL345"
#endif
#if defined(FEATURE_I2C_LCD) && !defined(FEATURE_WIRE_SUPPORT)
#define FEATURE_WIRE_SUPPORT
#endif
#if (defined(FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB)||defined(FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB)||defined(FEATURE_EL_POSITION_LSM303)||defined(FEATURE_AZ_POSITION_LSM303)) && !defined(FEATURE_WIRE_SUPPORT)
#define FEATURE_WIRE_SUPPORT
#endif
#ifdef FEATURE_WIRE_SUPPORT
#include <Wire.h>
#endif
#if defined(FEATURE_REMOTE_UNIT_SLAVE) && defined(FEATURE_YAESU_EMULATION)
#error "You must turn off FEATURE_YAESU_EMULATION if using FEATURE_REMOTE_UNIT_SLAVE"
#endif
#if defined(FEATURE_REMOTE_UNIT_SLAVE) && defined(FEATURE_EASYCOM_EMULATION)
#error "You must turn off FEATURE_EASYCOM_EMULATION if using FEATURE_REMOTE_UNIT_SLAVE"
#endif
#if !defined(FEATURE_ELEVATION_CONTROL) && defined(FEATURE_EL_PRESET_ENCODER)
#undef FEATURE_EL_PRESET_ENCODER
#endif
#if !defined(FEATURE_AZ_POSITION_POTENTIOMETER) && !defined(FEATURE_AZ_POSITION_ROTARY_ENCODER) && !defined(FEATURE_AZ_POSITION_PULSE_INPUT) && !defined(FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT) && !defined(FEATURE_AZ_POSITION_HMC5883L) && !defined(FEATURE_AZ_POSITION_LSM303)
#error "You must specify one AZ position sensor feature"
#endif
#if defined(FEATURE_ELEVATION_CONTROL) && !defined(FEATURE_EL_POSITION_POTENTIOMETER) && !defined(FEATURE_EL_POSITION_ROTARY_ENCODER) && !defined(FEATURE_EL_POSITION_PULSE_INPUT) && !defined(FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB) && !defined(FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB) && !defined(FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT) && !defined(FEATURE_EL_POSITION_LSM303)
#error "You must specify one EL position sensor feature"
#endif
#if (defined(FEATURE_AZ_PRESET_ENCODER) || defined(FEATURE_EL_PRESET_ENCODER) || defined(FEATURE_AZ_POSITION_ROTARY_ENCODER) || defined(FEATURE_EL_POSITION_ROTARY_ENCODER)) && !defined(FEATURE_ROTARY_ENCODER_SUPPORT)
#define FEATURE_ROTARY_ENCODER_SUPPORT
#endif
#if defined(FEATURE_REMOTE_UNIT_SLAVE) && !defined(FEATURE_ONE_DECIMAL_PLACE_HEADINGS)
#define FEATURE_ONE_DECIMAL_PLACE_HEADINGS
#endif
/*---------------------- macros - don't touch these unless you know what you are doing ---------------------*/
#define AZ 1
#define EL 2
#ifdef FEATURE_ROTARY_ENCODER_SUPPORT
#define DIR_CCW 0x10 // CW Encoder Code (Do not change)
#define DIR_CW 0x20 // CCW Encoder Code (Do not change)
#endif //FEATURE_ROTARY_ENCODER_SUPPORT
#define BRAKE_RELEASE_OFF 0
#define BRAKE_RELEASE_ON 1
//az_state
#define IDLE 0
#define SLOW_START_CW 1
#define SLOW_START_CCW 2
#define NORMAL_CW 3
#define NORMAL_CCW 4
#define SLOW_DOWN_CW 5
#define SLOW_DOWN_CCW 6
#define INITIALIZE_SLOW_START_CW 7
#define INITIALIZE_SLOW_START_CCW 8
#define INITIALIZE_TIMED_SLOW_DOWN_CW 9
#define INITIALIZE_TIMED_SLOW_DOWN_CCW 10
#define TIMED_SLOW_DOWN_CW 11
#define TIMED_SLOW_DOWN_CCW 12
#define INITIALIZE_DIR_CHANGE_TO_CW 13
#define INITIALIZE_DIR_CHANGE_TO_CCW 14
#define INITIALIZE_NORMAL_CW 15
#define INITIALIZE_NORMAL_CCW 16
//el_state
#define SLOW_START_UP 1
#define SLOW_START_DOWN 2
#define NORMAL_UP 3
#define NORMAL_DOWN 4
#define SLOW_DOWN_DOWN 5
#define SLOW_DOWN_UP 6
#define INITIALIZE_SLOW_START_UP 7
#define INITIALIZE_SLOW_START_DOWN 8
#define INITIALIZE_TIMED_SLOW_DOWN_UP 9
#define INITIALIZE_TIMED_SLOW_DOWN_DOWN 10
#define TIMED_SLOW_DOWN_UP 11
#define TIMED_SLOW_DOWN_DOWN 12
#define INITIALIZE_DIR_CHANGE_TO_UP 13
#define INITIALIZE_DIR_CHANGE_TO_DOWN 14
#define INITIALIZE_NORMAL_UP 15
#define INITIALIZE_NORMAL_DOWN 16
//az_request & el_request
#define REQUEST_STOP 0
#define REQUEST_AZIMUTH 1
#define REQUEST_AZIMUTH_RAW 2
#define REQUEST_CW 3
#define REQUEST_CCW 4
#define REQUEST_UP 1
#define REQUEST_DOWN 2
#define REQUEST_ELEVATION 3
#define REQUEST_KILL 5
#define DEACTIVATE 0
#define ACTIVATE 1
#define CW 1
#define CCW 2
#define STOP_AZ 3
#define STOP_EL 4
#define UP 5
#define DOWN 6
#define STOP 7
//az_request_queue_state & el_request_queue_state
#define NONE 0
#define IN_QUEUE 1
#define IN_PROGRESS_TIMED 2
#define IN_PROGRESS_TO_TARGET 3
#define EMPTY 0
#define LOADED_AZIMUTHS 1
#define RUNNING_AZIMUTHS 2
#ifdef FEATURE_ELEVATION_CONTROL
#define LOADED_AZIMUTHS_ELEVATIONS 3
#define RUNNING_AZIMUTHS_ELEVATIONS 4
#endif //FEATURE_ELEVATION_CONTROL
#define LCD_UNDEF 0
#define LCD_HEADING 1
#define LCD_DIRECTION 2
#define LCD_TARGET_AZ 3
#define LCD_TARGET_EL 4
#define LCD_TARGET_AZ_EL 5
#define LCD_ROTATING_CW 6
#define LCD_ROTATING_CCW 7
#define LCD_ROTATING_TO 8
#define LCD_ELEVATING_TO 9
#define LCD_ELEVATING_UP 10
#define LCD_ELEVATING_DOWN 11
#define LCD_ROTATING_AZ_EL 12
#define NOT_DOING_ANYTHING 0
#define ROTATING_CW 1
#define ROTATING_CCW 2
#define ROTATING_UP 3
#define ROTATING_DOWN 4
#define REMOTE_UNIT_NO_COMMAND 0
#define REMOTE_UNIT_AZ_COMMAND 1
#define REMOTE_UNIT_EL_COMMAND 2
/* ------end of macros ------- */
/* --------------------------- Settings ------------------------------------------------
You can tweak these, but read the online documentation!
*/
// analog voltage calibration - these are default values; you can either tweak these or set via the Yaesu O and F commands (and O2 and F2)....
#define ANALOG_AZ_FULL_CCW 4
#define ANALOG_AZ_FULL_CW 1009
#define ANALOG_EL_0_DEGREES 2
#define ANALOG_EL_MAX_ELEVATION 1018 // maximum elevation is normally 180 degrees unless change below for ELEVATION_MAXIMUM_DEGREES
#define ANALOG_AZ_OVERLAP_DEGREES 540 // if overlap_led above is enabled, turn on overlap led line if azimuth is greater than this setting
// you must use raw azimuth (if the azimuth on the rotator crosses over to 0 degrees, add 360
// for example, on a Yaesu 450 degree rotator with a starting point of 180 degrees, and an overlap LED
// turning on when going CW and crossing 180, ANALOG_AZ_OVERLAP_DEGREES should be set for 540 (180 + 360)
// PWM speed voltage settings
#define PWM_SPEED_VOLTAGE_X1 64
#define PWM_SPEED_VOLTAGE_X2 128
#define PWM_SPEED_VOLTAGE_X3 191
#define PWM_SPEED_VOLTAGE_X4 255
//AZ
#define AZ_SLOWSTART_DEFAULT 0 // 0 = off ; 1 = on
#define AZ_SLOWDOWN_DEFAULT 0 // 0 = off ; 1 = on
#define AZ_SLOW_START_UP_TIME 2000 // if slow start is enabled, the unit will ramp up speed for this many milliseconds
#define AZ_SLOW_START_STARTING_PWM 1 // PWM starting value for slow start
#define AZ_SLOW_START_STEPS 20
#define SLOW_DOWN_BEFORE_TARGET_AZ 10.0 // if slow down is enabled, slowdown will be activated within this many degrees of target azimuth
#define AZ_SLOW_DOWN_PWM_START 200 // starting PWM value for slow down
#define AZ_SLOW_DOWN_PWM_STOP 20 // ending PWM value for slow down
#define AZ_SLOW_DOWN_STEPS 20
//EL
#define EL_SLOWSTART_DEFAULT 0 // 0 = off ; 1 = on
#define EL_SLOWDOWN_DEFAULT 0 // 0 = off ; 1 = on
#define EL_SLOW_START_UP_TIME 2000 // if slow start is enabled, the unit will ramp up speed for this many milliseconds
#define EL_SLOW_START_STARTING_PWM 1 // PWM starting value for slow start
#define EL_SLOW_START_STEPS 20
#define SLOW_DOWN_BEFORE_TARGET_EL 10.0 // if slow down is enabled, slowdown will be activated within this many degrees of target azimuth
#define EL_SLOW_DOWN_PWM_START 200 // starting PWM value for slow down
#define EL_SLOW_DOWN_PWM_STOP 20 // ending PWM value for slow down
#define EL_SLOW_DOWN_STEPS 20
#define TIMED_SLOW_DOWN_TIME 2000
//Variable frequency output settings
#define AZ_VARIABLE_FREQ_OUTPUT_LOW 1 // Frequency in hertz of minimum speed
#define AZ_VARIABLE_FREQ_OUTPUT_HIGH 50 // Frequency in hertz of maximum speed
#define EL_VARIABLE_FREQ_OUTPUT_LOW 1 // Frequency in hertz of minimum speed
#define EL_VARIABLE_FREQ_OUTPUT_HIGH 50 // Frequency in hertz of maximum speed
// Settings for OPTION_AZ_MANUAL_ROTATE_LIMITS
#define AZ_MANUAL_ROTATE_CCW_LIMIT 0 // if using a rotator that starts at 180 degrees, set this to something like 185
#define AZ_MANUAL_ROTATE_CW_LIMIT 535 // add 360 to this if you go past 0 degrees (i.e. 180 CW after 0 degrees = 540)
// Settings for OPTION_EL_MANUAL_ROTATE_LIMITS
#define EL_MANUAL_ROTATE_DOWN_LIMIT -1
#define EL_MANUAL_ROTATE_UP_LIMIT 181
// Speed pot settings
#define SPEED_POT_LOW 0
#define SPEED_POT_HIGH 1023
#define SPEED_POT_LOW_MAP 1
#define SPEED_POT_HIGH_MAP 255
// Azimuth preset pot settings
#define AZ_PRESET_POT_FULL_CW 0
#define AZ_PRESET_POT_FULL_CCW 1023
#define AZ_PRESET_POT_FULL_CW_MAP 180 // azimuth pot fully counter-clockwise degrees
#define AZ_PRESET_POT_FULL_CCW_MAP 630 // azimuth pot fully clockwise degrees
#define ENCODER_PRESET_TIMEOUT 5000
// various code settings
#define AZIMUTH_TOLERANCE 3.0 // rotator will stop within X degrees when doing autorotation
#define ELEVATION_TOLERANCE 1.0
#define OPERATION_TIMEOUT 60000 // timeout for any rotation operation in mS ; 60 seconds is usually enough unless you have the speed turned down
#define TIMED_INTERVAL_ARRAY_SIZE 20
#define SERIAL_BAUD_RATE 115200 //9600 // 9600
#define SERIAL1_BAUD_RATE 9600 // 9600
#define SERIAL2_BAUD_RATE 9600 // 9600
#define SERIAL3_BAUD_RATE 9600 // 9600
#define LCD_UPDATE_TIME 1000 // LCD update time in milliseconds
#define AZ_BRAKE_DELAY 3000 // in milliseconds
#define EL_BRAKE_DELAY 3000 // in milliseconds
#define EEPROM_MAGIC_NUMBER 100
#define EEPROM_WRITE_DIRTY_CONFIG_TIME 30 //time in seconds
#ifdef FEATURE_ONE_DECIMAL_PLACE_HEADINGS
#define HEADING_MULTIPLIER 10
#define LCD_HEADING_MULTIPLIER 10.0
#define LCD_DECIMAL_PLACES 1
#else //FEATURE_ONE_DECIMAL_PLACE_HEADINGS
#define HEADING_MULTIPLIER 1
#define LCD_HEADING_MULTIPLIER 1.0
#define LCD_DECIMAL_PLACES 0
#endif //FEATURE_ONE_DECIMAL_PLACE_HEADINGS
#define AZ_POSITION_ROTARY_ENCODER_DEG_PER_PULSE 0.5
#define EL_POSITION_ROTARY_ENCODER_DEG_PER_PULSE 0.5
#define AZ_POSITION_PULSE_DEG_PER_PULSE 0.5
#define EL_POSITION_PULSE_DEG_PER_PULSE 0.5
#define PARK_AZIMUTH 0.0
#define PARK_ELEVATION 0.0
#define COMMAND_BUFFER_SIZE 50
#define REMOTE_BUFFER_TIMEOUT_MS 250
#define REMOTE_UNIT_COMMAND_TIMEOUT_MS 2000
#define AZ_REMOTE_UNIT_QUERY_TIME_MS 150 // how often we query the remote remote for azimuth
#define EL_REMOTE_UNIT_QUERY_TIME_MS 150 // how often we query the remote remote for elevation
#define ROTATE_PIN_INACTIVE_VALUE LOW
#define ROTATE_PIN_ACTIVE_VALUE HIGH
#define AZIMUTH_SMOOTHING_FACTOR 0 // value = 0 to 99.9
#define ELEVATION_SMOOTHING_FACTOR 0 // value = 0 to 99.9
#define AZIMUTH_MEASUREMENT_FREQUENCY_MS 0 // this does not apply if using FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
#define ELEVATION_MEASUREMENT_FREQUENCY_MS 0 // this does not apply if using FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
#define JOYSTICK_WAIT_TIME_MS 100
#define ROTATION_INDICATOR_PIN_ACTIVE_STATE HIGH
#define ROTATION_INDICATOR_PIN_INACTIVE_STATE LOW
#define ROTATION_INDICATOR_PIN_TIME_DELAY_SECONDS 0
#define ROTATION_INDICATOR_PIN_TIME_DELAY_MINUTES 0
/*----------------------- variables -------------------------------------*/
int azimuth = 0;
int raw_azimuth = 0;
int target_azimuth = 0;
int target_raw_azimuth = 0;
byte incoming_serial_byte = 0;
byte serial0_buffer[COMMAND_BUFFER_SIZE];
int serial0_buffer_index = 0;
byte az_state = IDLE;
byte debug_mode = DEFAULT_DEBUG_STATE;
int analog_az = 0;
unsigned long last_debug_output_time = 0;
unsigned long az_last_rotate_initiation = 0;
byte azimuth_button_was_pushed = 0;
byte brake_az_engaged = 0;
byte brake_el_engaged = 0;
byte configuration_dirty = 0;
unsigned long last_serial_receive_time = 0;
byte az_slowstart_active = AZ_SLOWSTART_DEFAULT;
byte az_slowdown_active = AZ_SLOWDOWN_DEFAULT;
byte az_request = 0;
int az_request_parm = 0;
byte az_request_queue_state = NONE;
unsigned long az_slowstart_start_time = 0;
byte az_slow_start_step = 0;
unsigned long az_last_step_time = 0;
byte az_slow_down_step = 0;
unsigned long az_timed_slow_down_start_time = 0;
byte backslash_command = 0;
struct config_t {
byte magic_number;
int analog_az_full_ccw;
int analog_az_full_cw;
int analog_el_0_degrees;
int analog_el_max_elevation;
int azimuth_starting_point;
int azimuth_rotation_capability;
float last_azimuth;
float last_elevation;
} configuration;
#ifdef FEATURE_TIMED_BUFFER
int timed_buffer_azimuths[TIMED_INTERVAL_ARRAY_SIZE];
int timed_buffer_number_entries_loaded = 0;
int timed_buffer_entry_pointer = 0;
int timed_buffer_interval_value_seconds = 0;
unsigned long last_timed_buffer_action_time = 0;
byte timed_buffer_status = 0;
#endif //FEATURE_TIMED_BUFFER
byte normal_az_speed_voltage = 0;
byte current_az_speed_voltage = 0;
#ifdef FEATURE_ELEVATION_CONTROL
int elevation = 0;
int target_elevation = 0;
byte el_request = 0;
int el_request_parm = 0;
byte el_request_queue_state = NONE;
byte el_slowstart_active = EL_SLOWSTART_DEFAULT;
byte el_slowdown_active = EL_SLOWDOWN_DEFAULT;
unsigned long el_slowstart_start_time = 0;
byte el_slow_start_step = 0;
unsigned long el_last_step_time = 0;
byte el_slow_down_step = 0;
unsigned long el_timed_slow_down_start_time = 0;
byte normal_el_speed_voltage = 0;
byte current_el_speed_voltage = 0;
int display_elevation = 0; // Variable added to handle elevation beyond 90 degrees. /// W3SA
byte el_state = IDLE;
int analog_el = 0;
unsigned long el_last_rotate_initiation = 0;
#ifdef FEATURE_TIMED_BUFFER
int timed_buffer_elevations[TIMED_INTERVAL_ARRAY_SIZE];
#endif //FEATURE_TIMED_BUFFER
byte elevation_button_was_pushed = 0;
#endif
#ifdef FEATURE_LCD_DISPLAY
unsigned long last_lcd_update = 0;
String last_direction_string;
byte push_lcd_update = 0;
#define LCD_COLUMNS 16
//#define LCD_COLUMNS 20
#ifdef FEATURE_I2C_LCD
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7
byte lcdcolor = GREEN; // default color of I2C LCD display
#endif //FEATURE_I2C_LCD
#endif //FEATURE_LCD_DISPLAY
#ifdef FEATURE_ROTARY_ENCODER_SUPPORT
#ifdef OPTION_ENCODER_HALF_STEP_MODE // Use the half-step state table (emits a code at 00 and 11)
const unsigned char ttable[6][4] = {
{0x3 , 0x2, 0x1, 0x0}, {0x23, 0x0, 0x1, 0x0},
{0x13, 0x2, 0x0, 0x0}, {0x3 , 0x5, 0x4, 0x0},
{0x3 , 0x3, 0x4, 0x10}, {0x3 , 0x5, 0x3, 0x20}
};
#else // Use the full-step state table (emits a code at 00 only)
const unsigned char ttable[7][4] = {
{0x0, 0x2, 0x4, 0x0}, {0x3, 0x0, 0x1, 0x10},
{0x3, 0x2, 0x0, 0x0}, {0x3, 0x2, 0x1, 0x0},
{0x6, 0x0, 0x4, 0x0}, {0x6, 0x5, 0x0, 0x10},
{0x6, 0x5, 0x4, 0x0},
};
#endif //OPTION_ENCODER_HALF_STEP_MODE
#ifdef FEATURE_AZ_PRESET_ENCODER // Rotary Encoder State Tables
int az_encoder_raw_degrees = 0;
#define ENCODER_IDLE 0
#define ENCODER_AZ_PENDING 1
#define ENCODER_EL_PENDING 2
#define ENCODER_AZ_EL_PENDING 3
volatile unsigned char az_encoder_state = 0;
#ifdef FEATURE_EL_PRESET_ENCODER
volatile unsigned char el_encoder_state = 0;
int el_encoder_degrees = 0;
#endif //FEATURE_EL_PRESET_ENCODER
byte preset_encoders_state = ENCODER_IDLE;
#endif //FEATURE_AZ_PRESET_ENCODER
#endif //FEATURE_ROTARY_ENCODER_SUPPORT
#ifdef DEBUG_PROFILE_LOOP_TIME
float average_loop_time = 0;
#endif //DEBUG_PROFILE_LOOP_TIME
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
volatile float az_position_pulse_input_azimuth = 0;
volatile byte last_known_az_state = 0;
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
volatile float el_position_pulse_input_elevation = 0;
volatile byte last_known_el_state = 0;
#endif //FEATURE_EL_POSITION_PULSE_INPUT
#ifdef FEATURE_REMOTE_UNIT_SLAVE
byte serial_read_event_flag[] = {0,0,0,0,0};
byte serial0_buffer_carriage_return_flag = 0;
#endif
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
byte serial1_buffer[COMMAND_BUFFER_SIZE];
int serial1_buffer_index = 0;
byte serial1_buffer_carriage_return_flag = 0;
unsigned long serial1_last_receive_time = 0;
byte remote_unit_command_submitted = 0;
unsigned long last_remote_unit_command_time = 0;
unsigned int remote_unit_command_timeouts = 0;
unsigned int remote_unit_bad_results = 0;
unsigned int remote_unit_good_results = 0;
unsigned int remote_unit_incoming_buffer_timeouts = 0;
byte remote_unit_command_results_available = 0;
float remote_unit_command_result_float = 0;
byte remote_port_rx_sniff = 0;
byte remote_port_tx_sniff = 0;
byte suspend_remote_commands = 0;
#endif
#ifdef DEBUG_POSITION_PULSE_INPUT
//unsigned int az_position_pule_interrupt_handler_flag = 0;
//unsigned int el_position_pule_interrupt_handler_flag = 0;
volatile unsigned long az_pulse_counter = 0;
volatile unsigned long el_pulse_counter = 0;
volatile unsigned int az_pulse_counter_ambiguous = 0;
volatile unsigned int el_pulse_counter_ambiguous = 0;
#endif //DEBUG_POSITION_PULSE_INPUT
/*
Azimuth and Elevation calibraton tables - use with FEATURE_AZIMUTH_CORRECTION and/or FEATURE_ELEVATION_CORRECTION
You must have the same number of entries in the _from and _to arrays!
*/
#ifdef FEATURE_AZIMUTH_CORRECTION
float azimuth_calibration_from[] = {180, 630}; /* these are in "raw" degrees, i.e. when going east past 360 degrees, add 360 degrees*/
float azimuth_calibration_to[] = {180, 630};
#endif //FEATURE_AZIMUTH_CORRECTION
#ifdef FEATURE_ELEVATION_CORRECTION
float elevation_calibration_from[] = {-180, 0, 180};
float elevation_calibration_to[] = { 180, 0, 180};
#endif //FEATURE_ELEVATION_CORRECTION
/* ------------------ let's start doing some stuff now that we got the formalities out of the way --------------------*/
void setup() {
delay(1000);
initialize_serial();
initialize_peripherals();
read_settings_from_eeprom();
initialize_pins();
read_azimuth();
#ifdef FEATURE_YAESU_EMULATION
report_current_azimuth(); // Yaesu - report the azimuth right off the bat without a C command; the Arduino doesn't wake up quick enough
// to get first C command from HRD and if HRD doesn't see anything it doesn't connect
#endif //FEATURE_YAESU_EMULATION
#ifdef FEATURE_TIMED_BUFFER
timed_buffer_status = EMPTY;
#endif //FEATURE_TIMED_BUFFER
#ifdef FEATURE_LCD_DISPLAY
initialize_display();
#endif
initialize_rotary_encoders();
initialize_interrupts();
}
/*-------------------------- here's where the magic happens --------------------------------*/
void loop() {
check_serial();
read_headings();
#ifndef FEATURE_REMOTE_UNIT_SLAVE
service_request_queue();
service_rotation();
az_check_operation_timeout();
#ifdef FEATURE_TIMED_BUFFER
check_timed_interval();
#endif //FEATURE_TIMED_BUFFER
read_headings();
check_buttons();
check_overlap();
check_brake_release();
#ifdef FEATURE_ELEVATION_CONTROL
el_check_operation_timeout();
#endif
#endif //ndef FEATURE_REMOTE_UNIT_SLAVE
read_headings();
#ifdef FEATURE_LCD_DISPLAY
update_display();
#endif
read_headings();
#ifndef FEATURE_REMOTE_UNIT_SLAVE
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
check_az_manual_rotate_limit();
#endif
#ifdef OPTION_EL_MANUAL_ROTATE_LIMITS
check_el_manual_rotate_limit();
#endif
check_az_speed_pot();
#ifdef FEATURE_AZ_PRESET_ENCODER // Rotary Encoder or Preset Selector
check_preset_encoders();
#else
check_az_preset_potentiometer();
#endif //FEATURE_AZ_PRESET_ENCODER
#endif //ndef FEATURE_REMOTE_UNIT_SLAVE
output_debug();
check_for_dirty_configuration();
read_headings();
profile_loop_time();
#ifdef FEATURE_REMOTE_UNIT_SLAVE
service_remote_unit_serial_buffer();
#endif //FEATURE_REMOTE_UNIT_SLAVE
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
service_remote_communications_incoming_serial_buffer();
#endif //FEATURE_HOST_REMOTE_PROTOCOL
#ifdef FEATURE_JOYSTICK_CONTROL
check_joystick();
#endif //FEATURE_JOYSTICK_CONTROL
#ifdef FEATURE_ROTATION_INDICATOR_PIN
service_rotation_indicator_pin();
#endif //FEATURE_ROTATION_INDICATOR_PIN
service_blink_led();
}
/* -------------------------------------- subroutines -----------------------------------------------
Where the real work happens...
*/
void read_headings(){
read_azimuth();
#ifdef FEATURE_ELEVATION_CONTROL
read_elevation();
#endif
}
//--------------------------------------------------------------
void service_blink_led(){
static unsigned long last_blink_led_transition = 0;
static byte blink_led_status = 0;
#ifdef blink_led
if ((millis() - last_blink_led_transition) >= 1000){
if (blink_led_status){
digitalWrite(blink_led,LOW);
blink_led_status = 0;
} else {
digitalWrite(blink_led,HIGH);
blink_led_status = 1;
}
last_blink_led_transition = millis();
}
#endif //blink_led
}
//--------------------------------------------------------------
void profile_loop_time(){
#ifdef DEBUG_PROFILE_LOOP_TIME
static unsigned long last_time = 0;
static unsigned long last_print_time = 0;
average_loop_time = (average_loop_time + (millis()-last_time))/2.0;
last_time = millis();
if (debug_mode){
if ((millis()-last_print_time) > 1000){
Serial.print(F("avg loop time: "));
Serial.println(average_loop_time,2);
last_print_time = millis();
}
}
#endif //DEBUG_PROFILE_LOOP_TIME
}
//--------------------------------------------------------------
void check_az_speed_pot() {
static unsigned long last_pot_check_time = 0;
int pot_read = 0;
byte new_azimuth_speed_voltage = 0;
if (az_speed_pot && azimuth_speed_voltage && ((millis() - last_pot_check_time) > 500)) {
pot_read = analogRead(az_speed_pot);
new_azimuth_speed_voltage = map(pot_read, SPEED_POT_LOW, SPEED_POT_HIGH, SPEED_POT_LOW_MAP, SPEED_POT_HIGH_MAP);
if (new_azimuth_speed_voltage != normal_az_speed_voltage) {
#ifdef DEBUG_AZ_SPEED_POT
if (debug_mode) {
Serial.print(F("check_az_speed_pot: normal_az_speed_voltage: "));
Serial.print(normal_az_speed_voltage);
Serial.print(F(" new_azimuth_speed_voltage:"));
Serial.println(new_azimuth_speed_voltage);
}
#endif //DEBUG_AZ_SPEED_POT
//analogWrite(azimuth_speed_voltage, new_azimuth_speed_voltage);
normal_az_speed_voltage = new_azimuth_speed_voltage;
update_az_variable_outputs(normal_az_speed_voltage);
#if defined(OPTION_EL_SPEED_FOLLOWS_AZ_SPEED) && defined(FEATURE_ELEVATION_CONTROL)
normal_el_speed_voltage = new_azimuth_speed_voltage;
update_el_variable_outputs(normal_el_speed_voltage);
#endif //OPTION_EL_SPEED_FOLLOWS_AZ_SPEED
}
last_pot_check_time = millis();
}
}
//--------------------------------------------------------------
void check_az_preset_potentiometer() {
byte check_pot = 0;
static unsigned long last_pot_check_time = 0;
static int last_pot_read = 9999;
int pot_read = 0;
int new_pot_azimuth = 0;
byte button_read = 0;
static byte pot_changed_waiting = 0;
if (az_preset_pot){
if (last_pot_read == 9999) { // initialize last_pot_read the first time we hit this subroutine
last_pot_read = analogRead(az_preset_pot);
}
if (!pot_changed_waiting) {
if (preset_start_button) { // if we have a preset start button, check it
button_read = digitalRead(preset_start_button);
if (button_read == LOW) {check_pot = 1;}
} else { // if not, check the pot every 500 mS
if ((millis() - last_pot_check_time) < 250) {check_pot = 1;}
}
if (check_pot) {
pot_read = analogRead(az_preset_pot);
new_pot_azimuth = map(pot_read, AZ_PRESET_POT_FULL_CW, AZ_PRESET_POT_FULL_CCW, AZ_PRESET_POT_FULL_CW_MAP, AZ_PRESET_POT_FULL_CCW_MAP);
if ((abs(last_pot_read - pot_read) > 4) && (abs(new_pot_azimuth - (raw_azimuth/HEADING_MULTIPLIER)) > AZIMUTH_TOLERANCE)) {
pot_changed_waiting = 1;
if (debug_mode) {Serial.println(F("check_az_preset_potentiometer: in pot_changed_waiting"));}
last_pot_read = pot_read;
}
}
last_pot_check_time = millis();
} else { // we're in pot change mode
pot_read = analogRead(az_preset_pot);
if (abs(pot_read - last_pot_read) > 3) { // if the pot has changed, reset the timer
last_pot_check_time = millis();
last_pot_read = pot_read;
} else {
if ((millis() - last_pot_check_time) >= 250) { // has it been awhile since the last pot change?
new_pot_azimuth = map(pot_read, AZ_PRESET_POT_FULL_CW, AZ_PRESET_POT_FULL_CCW, AZ_PRESET_POT_FULL_CW_MAP, AZ_PRESET_POT_FULL_CCW_MAP);
#ifdef DEBUG_AZ_PRESET_POT
if (debug_mode) {
Serial.print(F("check_az_preset_potentiometer: pot change - current raw_azimuth: "));
Serial.print(raw_azimuth/HEADING_MULTIPLIER);
Serial.print(F(" new_azimuth: "));
Serial.println(new_pot_azimuth);
}
#endif //DEBUG_AZ_PRESET_POT
submit_request(AZ,REQUEST_AZIMUTH_RAW,new_pot_azimuth*HEADING_MULTIPLIER);
pot_changed_waiting = 0;
last_pot_read = pot_read;
last_pot_check_time = millis();
}
}
}
} //if (az_preset_pot)
}
//--------------------------------------------------------------
void initialize_rotary_encoders(){
#ifdef FEATURE_AZ_PRESET_ENCODER
pinMode(az_rotary_preset_pin1, INPUT);
pinMode(az_rotary_preset_pin2, INPUT);
az_encoder_raw_degrees = raw_azimuth;
#ifdef OPTION_ENCODER_ENABLE_PULLUPS
digitalWrite(az_rotary_preset_pin1, HIGH);
digitalWrite(az_rotary_preset_pin2, HIGH);
#endif //OPTION_ENCODER_ENABLE_PULLUPS
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
pinMode(el_rotary_preset_pin1, INPUT);
pinMode(el_rotary_preset_pin2, INPUT);
el_encoder_degrees = elevation;
#ifdef OPTION_ENCODER_ENABLE_PULLUPS
digitalWrite(el_rotary_preset_pin1, HIGH);
digitalWrite(el_rotary_preset_pin2, HIGH);
#endif //OPTION_ENCODER_ENABLE_PULLUPS
#endif //FEATURE_EL_PRESET_ENCODER
#ifdef FEATURE_AZ_POSITION_ROTARY_ENCODER
pinMode(az_rotary_position_pin1, INPUT);
pinMode(az_rotary_position_pin2, INPUT);
#ifdef OPTION_ENCODER_ENABLE_PULLUPS
digitalWrite(az_rotary_position_pin1, HIGH);
digitalWrite(az_rotary_position_pin2, HIGH);
#endif //OPTION_ENCODER_ENABLE_PULLUPS
#endif //FEATURE_AZ_POSITION_ROTARY_ENCODER
#ifdef FEATURE_EL_POSITION_ROTARY_ENCODER
pinMode(el_rotary_position_pin1, INPUT);
pinMode(el_rotary_position_pin2, INPUT);
#ifdef OPTION_ENCODER_ENABLE_PULLUPS
digitalWrite(el_rotary_position_pin1, HIGH);
digitalWrite(el_rotary_position_pin2, HIGH);
#endif //OPTION_ENCODER_ENABLE_PULLUPS
#endif //FEATURE_EL_POSITION_ROTARY_ENCODER
}
//--------------------------------------------------------------
#ifdef FEATURE_AZ_PRESET_ENCODER
void check_preset_encoders(){
static unsigned long last_encoder_change_time = 0;
byte button_read = 0;
byte number_columns = 0;
static byte submit_encoder_change = 0;
static unsigned long last_preset_start_button_start = 0;
static unsigned long last_preset_start_button_kill = 0;
static unsigned long last_encoder_move = 0;
#ifdef FEATURE_AZ_PRESET_ENCODER
static unsigned long az_timestamp[5];
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
static unsigned long el_timestamp[5];
#endif //FEATURE_EL_PRESET_ENCODER
#ifdef FEATURE_AZ_PRESET_ENCODER
az_encoder_state = ttable[az_encoder_state & 0xf][((digitalRead(az_rotary_preset_pin2) << 1) | digitalRead(az_rotary_preset_pin1))];
unsigned char az_encoder_result = az_encoder_state & 0x30;
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
el_encoder_state = ttable[el_encoder_state & 0xf][((digitalRead(el_rotary_preset_pin2) << 1) | digitalRead(el_rotary_preset_pin1))];
unsigned char el_encoder_result = el_encoder_state & 0x30;
#endif //FEATURE_EL_PRESET_ENCODER
#ifdef FEATURE_AZ_PRESET_ENCODER
if (az_encoder_result) { // If rotary encoder modified
az_timestamp[0] = az_timestamp[1]; // Encoder step timer
az_timestamp[1] = az_timestamp[2];
az_timestamp[2] = az_timestamp[3];
az_timestamp[3] = az_timestamp[4];
az_timestamp[4] = millis();
last_encoder_move = millis();
unsigned long az_elapsed_time = (az_timestamp[4] - az_timestamp[0]); // Encoder step time difference for 10's step
#ifdef OPTION_PRESET_ENCODER_RELATIVE_CHANGE
if ((preset_encoders_state == ENCODER_IDLE) || (preset_encoders_state == ENCODER_EL_PENDING)) {
if (az_request_queue_state == IN_PROGRESS_TO_TARGET) {
az_encoder_raw_degrees = target_raw_azimuth;
} else {
az_encoder_raw_degrees = raw_azimuth;
}
}
#endif //OPTION_PRESET_ENCODER_RELATIVE_CHANGE
//bbbbbb
if (az_encoder_result == DIR_CW) {
if (az_elapsed_time < 250 /* mSec */) {az_encoder_raw_degrees += (5*HEADING_MULTIPLIER);} else {az_encoder_raw_degrees += (1*HEADING_MULTIPLIER);}; // Single deg increase unless encoder turned quickly then 10's step
//if (az_encoder_raw_degrees >=(360*HEADING_MULTIPLIER)) {az_encoder_raw_degrees -= (360*HEADING_MULTIPLIER);};
if (az_encoder_raw_degrees >((configuration.azimuth_starting_point+configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER)) {
az_encoder_raw_degrees =
((configuration.azimuth_starting_point*HEADING_MULTIPLIER)
/* + ((configuration.azimuth_starting_point+configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER) - az_encoder_raw_degrees*/);
}
}
if (az_encoder_result == DIR_CCW) {
if (az_elapsed_time < 250 /* mSec */) {az_encoder_raw_degrees -= (5*HEADING_MULTIPLIER);} else {az_encoder_raw_degrees -= (1*HEADING_MULTIPLIER);}; // Single deg decrease unless encoder turned quickly then 10's step
//if (az_encoder_raw_degrees < 0) {az_encoder_raw_degrees = (360*HEADING_MULTIPLIER);};
if (az_encoder_raw_degrees < (configuration.azimuth_starting_point*HEADING_MULTIPLIER)) {
az_encoder_raw_degrees = (((configuration.azimuth_starting_point+configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER)
/*- (az_encoder_raw_degrees-(configuration.azimuth_starting_point*HEADING_MULTIPLIER))*/);
}
}
last_encoder_change_time = millis(); // Encoder Check Timer
#ifdef FEATURE_LCD_DISPLAY
push_lcd_update = 1; // push an LCD update
#endif //FEATURE_LCD_DISPLAY
if (preset_encoders_state == ENCODER_IDLE) {
preset_encoders_state = ENCODER_AZ_PENDING;
} else {
if (preset_encoders_state == ENCODER_EL_PENDING) {
preset_encoders_state = ENCODER_AZ_EL_PENDING;
}
}
#ifdef DEBUG_PRESET_ENCODERS
if (debug_mode) {
Serial.print(F("check_preset_encoders: az target: "));
Serial.println(az_encoder_raw_degrees/HEADING_MULTIPLIER,1);
}
#endif //DEBUG_PRESET_ENCODERS
} // if (az_encoder_result)
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
#ifdef OPTION_PRESET_ENCODER_RELATIVE_CHANGE
if ((preset_encoders_state == ENCODER_IDLE) || (preset_encoders_state == ENCODER_AZ_PENDING)) {
if (el_request_queue_state == IN_PROGRESS_TO_TARGET) {
el_encoder_degrees = target_elevation;
} else {
el_encoder_degrees = elevation;
}
}
#endif //OPTION_PRESET_ENCODER_RELATIVE_CHANGE
if (el_encoder_result) { // If rotary encoder modified
el_timestamp[0] = el_timestamp[1]; // Encoder step timer
el_timestamp[1] = el_timestamp[2];
el_timestamp[2] = el_timestamp[3];
el_timestamp[3] = el_timestamp[4];
el_timestamp[4] = millis();
last_encoder_move = millis();
unsigned long el_elapsed_time = (el_timestamp[4] - el_timestamp[0]); // Encoder step time difference for 10's step
if (el_encoder_result == DIR_CW) { // Rotary Encoder CW 0 - 359 Deg
if (el_elapsed_time < 250) {el_encoder_degrees += (5*HEADING_MULTIPLIER);} else {el_encoder_degrees += (1*HEADING_MULTIPLIER);}; // Single deg increase unless encoder turned quickly then 10's step
if (el_encoder_degrees > (180*HEADING_MULTIPLIER)) {el_encoder_degrees = (180*HEADING_MULTIPLIER);};
}
if (el_encoder_result == DIR_CCW) { // Rotary Encoder CCW 359 - 0 Deg
if (el_elapsed_time < 250) {el_encoder_degrees -= (5*HEADING_MULTIPLIER);} else {el_encoder_degrees -= (1*HEADING_MULTIPLIER);}; // Single deg decrease unless encoder turned quickly then 10's step
if (el_encoder_degrees < 0) {el_encoder_degrees = 0;};
}
last_encoder_change_time = millis(); // Encoder Check Timer
#ifdef FEATURE_LCD_DISPLAY
last_lcd_update = 0; // push an LCD update
#endif //FEATURE_LCD_DISPLAY
if (preset_encoders_state == ENCODER_IDLE) {
preset_encoders_state = ENCODER_EL_PENDING;
} else {
if (preset_encoders_state == ENCODER_AZ_PENDING) {
preset_encoders_state = ENCODER_AZ_EL_PENDING;
}
}
#ifdef DEBUG_PRESET_ENCODERS
if (debug_mode) {
Serial.print(F("check_preset_encoders: el target: "));
Serial.println(el_encoder_degrees/HEADING_MULTIPLIER,1);
}
#endif //DEBUG_PRESET_ENCODERS
} // if (el_encoder_result)
#endif //FEATURE_EL_PRESET_ENCODER
if ((preset_encoders_state != ENCODER_IDLE) && (!submit_encoder_change)) { // Check button or timer
if (preset_start_button) { // if we have a preset start button, check it
button_read = digitalRead(preset_start_button);
if (button_read == LOW) {
submit_encoder_change = 1;
last_preset_start_button_start = millis();
}
} else {
if ((millis() - last_encoder_change_time) > 2000) {submit_encoder_change = 1;} //if enc not changed for more than 2 sec, rotate to target
}
} //if (!enc_changed_waiting)
if (preset_start_button) { // if we have a preset start button, check it
button_read = digitalRead(preset_start_button);
if ((button_read == LOW) && (!submit_encoder_change) && ((millis() - last_preset_start_button_start) > 250)
&& ((millis() - last_preset_start_button_kill) > 250) && (preset_encoders_state == ENCODER_IDLE)) {
#ifdef DEBUG_PRESET_ENCODERS
if (debug_mode) {
Serial.println(F("check_preset_encoders: preset button kill"));
}
#endif //DEBUG_PRESET_ENCODERS
#ifdef FEATURE_AZ_PRESET_ENCODER
if (az_state != IDLE) {
submit_request(AZ,REQUEST_KILL,0);
}
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
if (el_state != IDLE) {
submit_request(EL,REQUEST_KILL,0);
}
#endif //FEATURE_EL_PRESET_ENCODER
last_preset_start_button_kill = millis();
}
}
if ((submit_encoder_change) && (button_read == HIGH)) {
#ifdef DEBUG_PRESET_ENCODERS
if (debug_mode) {
Serial.println(F("check_preset_encoders: submit_encoder_change "));
}
#endif //DEBUG_PRESET_ENCODERS
if ((preset_encoders_state == ENCODER_AZ_PENDING) || (preset_encoders_state == ENCODER_AZ_EL_PENDING)) {
submit_request(AZ,REQUEST_AZIMUTH_RAW,az_encoder_raw_degrees);
}
#ifdef FEATURE_EL_PRESET_ENCODER
if ((preset_encoders_state == ENCODER_EL_PENDING) || (preset_encoders_state == ENCODER_AZ_EL_PENDING)) {
submit_request(EL,REQUEST_ELEVATION,el_encoder_degrees);
}
#endif //FEATURE_EL_PRESET_ENCODER
preset_encoders_state = ENCODER_IDLE;
submit_encoder_change = 0;
} //if (submit_encoder_change)
if ((preset_start_button) && (preset_encoders_state != ENCODER_IDLE) && ((millis() - last_encoder_move) > ENCODER_PRESET_TIMEOUT)){ // timeout if we have a preset start button
preset_encoders_state = ENCODER_IDLE;
#ifdef FEATURE_LCD_DISPLAY
push_lcd_update = 1; // push an LCD update
#endif //FEATURE_LCD_DISPLAY
}
}
#endif //FEATURE_AZ_PRESET_ENCODER
//--------------------------------------------------------------
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
void check_az_manual_rotate_limit() {
if ((current_az_state() == ROTATING_CCW) && (raw_azimuth <= (AZ_MANUAL_ROTATE_CCW_LIMIT*HEADING_MULTIPLIER))) {
#ifdef DEBUG_AZ_MANUAL_ROTATE_LIMITS
if (debug_mode) {
Serial.print(F("check_az_manual_rotate_limit: stopping - hit AZ_MANUAL_ROTATE_CCW_LIMIT of "));
Serial.println(AZ_MANUAL_ROTATE_CCW_LIMIT);
}
#endif //DEBUG_AZ_MANUAL_ROTATE_LIMITS
submit_request(AZ,REQUEST_KILL,0);
}
if ((current_az_state() == ROTATING_CW) && (raw_azimuth >= (AZ_MANUAL_ROTATE_CW_LIMIT*HEADING_MULTIPLIER))) {
#ifdef DEBUG_AZ_MANUAL_ROTATE_LIMITS
if (debug_mode) {
Serial.print(F("check_az_manual_rotate_limit: stopping - hit AZ_MANUAL_ROTATE_CW_LIMIT of "));
Serial.println(AZ_MANUAL_ROTATE_CW_LIMIT);
}
#endif //DEBUG_AZ_MANUAL_ROTATE_LIMITS
submit_request(AZ,REQUEST_KILL,0);
}
}
#endif //#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
//--------------------------------------------------------------
#if defined(OPTION_EL_MANUAL_ROTATE_LIMITS) && defined(FEATURE_ELEVATION_CONTROL)
void check_el_manual_rotate_limit() {
if ((current_el_state() == ROTATING_DOWN) && (elevation <= (EL_MANUAL_ROTATE_DOWN_LIMIT*HEADING_MULTIPLIER))) {
#ifdef DEBUG_EL_MANUAL_ROTATE_LIMITS
if (debug_mode) {
Serial.print(F("check_el_manual_rotate_limit: stopping - hit EL_MANUAL_ROTATE_DOWN_LIMIT of "));
Serial.println(EL_MANUAL_ROTATE_DOWN_LIMIT);
}
#endif //DEBUG_EL_MANUAL_ROTATE_LIMITS
submit_request(EL,REQUEST_KILL,0);
}
if ((current_el_state() == ROTATING_UP) && (elevation >= (EL_MANUAL_ROTATE_UP_LIMIT*HEADING_MULTIPLIER))) {
#ifdef DEBUG_EL_MANUAL_ROTATE_LIMITS
if (debug_mode) {
Serial.print(F("check_el_manual_rotate_limit: stopping - hit EL_MANUAL_ROTATE_UP_LIMIT of "));
Serial.println(EL_MANUAL_ROTATE_UP_LIMIT);
}
#endif //DEBUG_EL_MANUAL_ROTATE_LIMITS
submit_request(EL,REQUEST_KILL,0);
}
}
#endif //#ifdef OPTION_EL_MANUAL_ROTATE_LIMITS
//--------------------------------------------------------------
void check_brake_release() {
static byte in_az_brake_release_delay = 0;
static unsigned long az_brake_delay_start_time = 0;
#ifdef FEATURE_ELEVATION_CONTROL
static byte in_el_brake_release_delay = 0;
static unsigned long el_brake_delay_start_time = 0;
#endif //FEATURE_ELEVATION_CONTROL
if ((az_state == IDLE) && (brake_az_engaged)) {
if (in_az_brake_release_delay) {
if ((millis() - az_brake_delay_start_time) > AZ_BRAKE_DELAY) {
brake_release(AZ, BRAKE_RELEASE_OFF);
in_az_brake_release_delay = 0;
}
} else {
az_brake_delay_start_time = millis();
in_az_brake_release_delay = 1;
}
}
#ifdef FEATURE_ELEVATION_CONTROL
if ((el_state == IDLE) && (brake_el_engaged)) {
if (in_el_brake_release_delay) {
if ((millis() - el_brake_delay_start_time) > EL_BRAKE_DELAY) {
brake_release(EL, BRAKE_RELEASE_OFF);
in_el_brake_release_delay = 0;
}
} else {
el_brake_delay_start_time = millis();
in_el_brake_release_delay = 1;
}
}
#endif //FEATURE_ELEVATION_CONTROL
}
//--------------------------------------------------------------
void brake_release(byte az_or_el, byte operation){
if (az_or_el == AZ) {
if (brake_az) {
if (operation == BRAKE_RELEASE_ON) {
digitalWrite(brake_az,HIGH);
brake_az_engaged = 1;
#ifdef DEBUG_BRAKE
if (debug_mode) {
Serial.println(F("brake_release: brake_az BRAKE_RELEASE_ON"));
}
#endif //DEBUG_BRAKE
} else {
digitalWrite(brake_az,LOW);
brake_az_engaged = 0;
#ifdef DEBUG_BRAKE
if (debug_mode) {
Serial.println(F("brake_release: brake_az BRAKE_RELEASE_OFF"));
}
#endif //DEBUG_BRAKE
}
}
} else {
#ifdef FEATURE_ELEVATION_CONTROL
if (brake_el) {
digitalWrite(brake_el,HIGH);
brake_el_engaged = 1;
#ifdef DEBUG_BRAKE
if (debug_mode) {
Serial.println(F("brake_release: brake_el BRAKE_RELEASE_ON"));
}
#endif //DEBUG_BRAKE
} else {
digitalWrite(brake_el,LOW);
brake_el_engaged = 0;
#ifdef DEBUG_BRAKE
if (debug_mode) {
Serial.println(F("brake_release: brake_el BRAKE_RELEASE_OFF"));
}
#endif //DEBUG_BRAKE
}
#endif //FEATURE_ELEVATION_CONTROL
}
}
//--------------------------------------------------------------
void check_overlap(){
static byte overlap_led_status = 0;
static unsigned long last_check_time;
if ((overlap_led) && ((millis() - last_check_time) > 500)) {
//if ((analog_az > (500*HEADING_MULTIPLIER)) && (azimuth > (ANALOG_AZ_OVERLAP_DEGREES*HEADING_MULTIPLIER)) && (!overlap_led_status)) {
if ((raw_azimuth > (ANALOG_AZ_OVERLAP_DEGREES*HEADING_MULTIPLIER)) && (!overlap_led_status)) {
digitalWrite(overlap_led, HIGH);
overlap_led_status = 1;
#ifdef DEBUG_OVERLAP
if (debug_mode) {
Serial.print(F("check_overlap: in overlap\r\n"));
}
#endif //DEBUG_OVERLAP
} else {
//if (((analog_az < (500*HEADING_MULTIPLIER)) || (azimuth < (ANALOG_AZ_OVERLAP_DEGREES*HEADING_MULTIPLIER))) && (overlap_led_status)) {
if ((raw_azimuth < (ANALOG_AZ_OVERLAP_DEGREES*HEADING_MULTIPLIER)) && (overlap_led_status)) {
digitalWrite(overlap_led, LOW);
overlap_led_status = 0;
#ifdef DEBUG_OVERLAP
if (debug_mode) {
Serial.print(F("check_overlap: overlap off\r\n"));
}
#endif //DEBUG_OVERLAP
}
}
last_check_time = millis();
}
}
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void yaesu_serial_command(){
if (incoming_serial_byte == 10) { return; } // ignore carriage returns
if ((incoming_serial_byte != 13) && (serial0_buffer_index < COMMAND_BUFFER_SIZE)) { // if it's not a carriage return, add it to the buffer
serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
serial0_buffer_index++;
} else { // we got a carriage return, time to get to work on the command
if ((serial0_buffer[0] > 96) && (serial0_buffer[0] < 123)) {
serial0_buffer[0] = serial0_buffer[0] - 32;
}
switch (serial0_buffer[0]) { // look at the first character of the command
case 'C': // C - return current azimuth
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: C cmd"));}
#endif //DEBUG_SERIAL
#ifdef OPTION_DELAY_C_CMD_OUTPUT
delay(400);
#endif
report_current_azimuth();
break;
case 'F': // F - full scale calibration
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: F cmd"));}
#endif //DEBUG_SERIAL
yaesu_f_command();
break;
case 'H': print_help(); break; // H - print help (simulated Yaesu GS-232A help - not all commands are supported
case 'L': // L - manual left (CCW) rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: L cmd"));}
#endif //DEBUG_SERIAL
submit_request(AZ,REQUEST_CCW,0);
Serial.println();
break;
case 'O': // O - offset calibration
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: O cmd"));}
#endif //DEBUG_SERIAL
yaesu_o_command();
break;
case 'R': // R - manual right (CW) rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: R cmd"));}
#endif //DEBUG_SERIAL
submit_request(AZ,REQUEST_CW,0);
Serial.println();
break;
case 'A': // A - CW/CCW rotation stop
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: A cmd"));}
#endif //DEBUG_SERIAL
submit_request(AZ,REQUEST_STOP,0);
Serial.println();
break;
case 'S': // S - all stop
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: S cmd"));}
#endif //DEBUG_SERIAL
submit_request(AZ,REQUEST_STOP,0);
#ifdef FEATURE_ELEVATION_CONTROL
submit_request(EL,REQUEST_STOP,0);
#endif
#ifdef FEATURE_TIMED_BUFFER
clear_timed_buffer();
#endif //FEATURE_TIMED_BUFFER
Serial.println();
break;
case 'M': // M - auto azimuth rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: M cmd"));}
#endif //DEBUG_SERIAL
yaesu_m_command();
break;
#ifdef FEATURE_TIMED_BUFFER
case 'N': // N - number of loaded timed interval entries
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: N cmd"));}
#endif //DEBUG_SERIAL
Serial.println(timed_buffer_number_entries_loaded);
break;
#endif //FEATURE_TIMED_BUFFER
#ifdef FEATURE_TIMED_BUFFER
case 'T': initiate_timed_buffer(); break; // T - initiate timed tracking
#endif //FEATURE_TIMED_BUFFER
case 'X': // X - azimuth speed change
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: X cmd"));}
#endif //DEBUG_SERIAL
yaesu_x_command();
break;
#ifdef FEATURE_ELEVATION_CONTROL
case 'U': // U - manual up rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: U cmd"));}
#endif //DEBUG_SERIAL
submit_request(EL,REQUEST_UP,0);
Serial.println();
break;
case 'D': // D - manual down rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: D cmd"));}
#endif //DEBUG_SERIAL
submit_request(EL,REQUEST_DOWN,0);
Serial.println();
break;
case 'E': // E - stop elevation rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: E cmd"));}
#endif //DEBUG_SERIAL
submit_request(EL,REQUEST_STOP,0);
Serial.println();
break;
case 'B': report_current_elevation(); break; // B - return current elevation
#endif
case 'W': // W - auto elevation rotation
#ifdef DEBUG_SERIAL
if (debug_mode) {Serial.println(F("yaesu_serial_command: W cmd"));}
#endif //DEBUG_SERIAL
yaesu_w_command();
break;
#ifdef OPTION_GS_232B_EMULATION
case 'P': yaesu_p_command(); break; // P - switch between 360 and 450 degree mode
case 'Z': // Z - Starting point toggle
if (configuration.azimuth_starting_point == 180) {
configuration.azimuth_starting_point = 0;
Serial.println(F("N Center"));
} else {
configuration.azimuth_starting_point = 180;
Serial.println(F("S Center"));
}
write_settings_to_eeprom();
break;
#endif
default:
Serial.println(F("?>"));
#ifdef DEBUG_SERIAL
if (debug_mode) {
Serial.print(F("check_serial: serial0_buffer_index: "));
Serial.println(serial0_buffer_index);
for (int debug_x = 0; debug_x < serial0_buffer_index; debug_x++) {
Serial.print(F("check_serial: serial0_buffer["));
Serial.print(debug_x);
Serial.print(F("]: "));
Serial.print(serial0_buffer[debug_x]);
Serial.print(F(" "));
Serial.write(serial0_buffer[debug_x]);
Serial.println();
}
}
#endif //DEBUG_SERIAL
}
clear_command_buffer();
}
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
void clear_command_buffer(){
serial0_buffer_index = 0;
serial0_buffer[0] = 0;
}
//--------------------------------------------------------------
#ifdef FEATURE_EASYCOM_EMULATION
void easycom_serial_commmand(){
/* Easycom protocol implementation
Implemented commands:
Command Meaning Parameters
------- ------- ----------
AZ Azimuth number - 1 decimal place
EL Elevation number - 1 decimal place
ML Move Left
MR Move Right
MU Move Up
MD Move Down
SA Stop azimuth moving
SE Stop elevation moving
VE Request Version
Easycom has no way to report azimuth or elevation back to the client, or report errors
*/
float heading = -1;
if ((incoming_serial_byte != 13) && (incoming_serial_byte != 10) && (incoming_serial_byte != 32) && (serial0_buffer_index < COMMAND_BUFFER_SIZE)){ // if it's not a CR, LF, or space, add it to the buffer
if ((incoming_serial_byte > 96) && (incoming_serial_byte < 123)) {incoming_serial_byte = incoming_serial_byte - 32;} //uppercase it
serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
serial0_buffer_index++;
} else { // time to get to work on the command
if (serial0_buffer_index){
switch (serial0_buffer[0]) { // look at the first character of the command
case 'A': //AZ
if (serial0_buffer[1] == 'Z'){ // format is AZx.x or AZxx.x or AZxxx.x (why didn't they make it fixed length?)
switch (serial0_buffer_index) {
#ifdef OPTION_EASYCOM_AZ_QUERY_COMMAND
case 2:
Serial.print("AZ");
Serial.println(float(azimuth*HEADING_MULTIPLIER),1);
clear_command_buffer();
return;
break;
#endif //OPTION_EASYCOM_AZ_QUERY_COMMAND
case 5: // format AZx.x
heading = (serial0_buffer[2]-48) + ((serial0_buffer[4]-48)/10);
break;
case 6: // format AZxx.x
heading = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48) + ((serial0_buffer[5]-48)/10);
break;
case 7: // format AZxxx.x
heading = ((serial0_buffer[2]-48)*100) + ((serial0_buffer[3]-48)*10) + (serial0_buffer[4]-48) + ((serial0_buffer[6]-48)/10);
break;
//default: Serial.println("?"); break;
}
if (((heading >= 0) && (heading < 451)) && (serial0_buffer[serial0_buffer_index-2] == '.')){
submit_request(AZ,REQUEST_AZIMUTH,(heading*HEADING_MULTIPLIER));
} else {
Serial.println("?");
}
} else {
Serial.println("?");
}
break;
#ifdef FEATURE_ELEVATION_CONTROL
case 'E': //EL
if (serial0_buffer[1] == 'L') {
switch (serial0_buffer_index) {
#ifdef OPTION_EASYCOM_EL_QUERY_COMMAND
case 2:
Serial.print("EL");
Serial.println(float(elevation*HEADING_MULTIPLIER),1);
clear_command_buffer();
return;
break;
#endif //OPTION_EASYCOM_EL_QUERY_COMMAND
case 5: // format ELx.x
heading = (serial0_buffer[2]-48) + ((serial0_buffer[4]-48)/10);
break;
case 6: // format ELxx.x
heading = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48) + ((serial0_buffer[5]-48)/10);
break;
case 7: // format ELxxx.x
heading = ((serial0_buffer[2]-48)*100) + ((serial0_buffer[3]-48)*10) + (serial0_buffer[4]-48) + ((serial0_buffer[6]-48)/10);
break;
//default: Serial.println("?"); break;
}
if (((heading >= 0) && (heading < 181)) && (serial0_buffer[serial0_buffer_index-2] == '.')){
submit_request(EL,REQUEST_ELEVATION,(heading*HEADING_MULTIPLIER));
} else {
Serial.println("?");
}
} else {
Serial.println(F("?"));
}
break;
#endif //#FEATURE_ELEVATION_CONTROL
case 'S': // SA or SE - stop azimuth, stop elevation
switch (serial0_buffer[1]) {
case 'A':
submit_request(AZ,REQUEST_STOP,0);
break;
#ifdef FEATURE_ELEVATION_CONTROL
case 'E':
submit_request(EL,REQUEST_STOP,0);
break;
#endif //FEATURE_ELEVATION_CONTROL
default: Serial.println("?"); break;
}
break;
case 'M': // ML, MR, MU, MD - move left, right, up, down
switch (serial0_buffer[1]){
case 'L': // ML - move left
submit_request(AZ,REQUEST_CCW,0);
break;
case 'R': // MR - move right
submit_request(AZ,REQUEST_CW,0);
break;
#ifdef FEATURE_ELEVATION_CONTROL
case 'U': // MU - move up
submit_request(EL,REQUEST_UP,0);
break;
case 'D': // MD - move down
submit_request(EL,REQUEST_DOWN,0);
break;
#endif //FEATURE_ELEVATION_CONTROL
default: Serial.println(F("?")); break;
}
break;
case 'V': // VE - version query
if (serial0_buffer[1] == 'E') {Serial.println(F("VE002"));} // not sure what to send back, sending 002 because this is easycom version 2?
break;
default: Serial.println("?"); break;
}
}
clear_command_buffer();
}
}
#endif //FEATURE_EASYCOM_EMULATION
//--------------------------------------------------------------
#if defined(FEATURE_REMOTE_UNIT_SLAVE) || defined(FEATURE_ANCILLARY_PIN_CONTROL)
byte get_analog_pin(byte pin_number){
byte return_output = 0;
switch(pin_number){
case 0: return_output = A0; break;
case 1: return_output = A1; break;
case 2: return_output = A2; break;
case 3: return_output = A3; break;
case 4: return_output = A4; break;
case 5: return_output = A5; break;
case 6: return_output = A6; break;
}
return return_output;
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
//--------------------------------------------------------------
#ifdef FEATURE_REMOTE_UNIT_SLAVE
void remote_unit_serial_command(){
if (serial_read_event_flag[0]){
Serial.print("EVS0");
Serial.write(incoming_serial_byte);
Serial.println();
}
if ((incoming_serial_byte != 10) && (serial0_buffer_index < COMMAND_BUFFER_SIZE)){
//incoming_serial_byte = toupper(incoming_serial_byte);
serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
serial0_buffer_index++;
if ((incoming_serial_byte == 13) || (serial0_buffer_index == COMMAND_BUFFER_SIZE)){
serial0_buffer_carriage_return_flag = 1;
}
}
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
//--------------------------------------------------------------
#ifdef FEATURE_REMOTE_UNIT_SLAVE
void service_remote_unit_serial_buffer(){
/*
This implements a protocol for host unit to remote unit communications
Remote Slave Unit Protocol Reference
PG - ping
AZ - read azimuth
EL - read elevation
DOxx - digital pin initialize as output;
DIxx - digital pin initialize as input
DPxx - digital pin initialize as input with pullup
DRxx - digital pin read
DLxx - digital pin write low
DHxx - digital pin write high
DTxxyyyy - digital pin tone output
NTxx - no tone
ARxx - analog pin read
AWxxyyy - analog pin write
SWxy - serial write byte
SDx - deactivate serial read event; x = port #
SSxyyyyyy... - serial write sting; x = port #, yyyy = string of characters to send
SAx - activate serial read event; x = port #
RB - reboot
Responses
ER - report an error (remote to host only)
EV - report an event (remote to host only)
OK - report success (remote to host only)
CS - report a cold start (remote to host only)
Error Codes
ER01 - Serial port buffer timeout
ER02 - Command syntax error
Events
EVSxy - Serial port read event; x = serial port number, y = byte returned
*/
String command_string;
byte command_good = 0;
if (serial0_buffer_carriage_return_flag) {
// TODO: if checksumming is turned on, parse out the checksum, validate it, return an error if invalid, chop it off if valid and continue
if (serial0_buffer_index < 3){
Serial.println(F("ER02")); // we don't have enough characters - syntax error
} else {
command_string = String(char(toupper(serial0_buffer[0]))) + String(char(toupper(serial0_buffer[1])));
#ifdef DEBUG_SERVICE_SERIAL_BUFFER
Serial.print(F("serial_serial_buffer: command_string: "));
Serial.print(command_string);
Serial.print(F("$ serial0_buffer_index: "));
Serial.println(serial0_buffer_index);
#endif //DEBUG_SERVICE_SERIAL_BUFFER
if ((command_string == "SS") && (serial0_buffer[2] > 47) && (serial0_buffer[2] < 53)){ // this is a variable length command
command_good = 1;
for (byte x = 3;x < serial0_buffer_index;x++){
switch(serial0_buffer[2]-48){
case 0: Serial.write(serial0_buffer[x]); break;
#ifdef OPTION_SERIAL1_SUPPORT
case 1: Serial1.write(serial0_buffer[x]); break;
#endif //OPTION_SERIAL1_SUPPORT
#ifdef OPTION_SERIAL2_SUPPORT
case 2: Serial2.write(serial0_buffer[x]); break;
#endif //OPTION_SERIAL1_SUPPORT
#ifdef OPTION_SERIAL3_SUPPORT
case 3: Serial3.write(serial0_buffer[x]); break;
#endif //OPTION_SERIAL1_SUPPORT
}
}
}
//yyyy
if (serial0_buffer_index == 3) {
if (command_string == "PG") {Serial.println(F("PG"));command_good = 1;} // PG - ping
if (command_string == "RB") {wdt_enable(WDTO_30MS); while(1) {}} // RB - reboot
if (command_string == "AZ") {
Serial.print(F("AZ"));
if (raw_azimuth < 1000) {Serial.print("0");}
if (raw_azimuth < 100) {Serial.print("0");}
if (raw_azimuth < 10) {Serial.print("0");}
Serial.println(raw_azimuth);
command_good = 1;
}
#ifdef FEATURE_ELEVATION_CONTROL
if (command_string == "EL") {
Serial.print(F("EL"));
if (elevation >= 0) {
Serial.print("+");
} else {
Serial.print("-");
}
if (abs(elevation) < 1000) {Serial.print("0");}
if (abs(elevation) < 100) {Serial.print("0");}
if (abs(elevation) < 10) {Serial.print("0");}
Serial.println(abs(elevation));
command_good = 1;
}
#endif //FEATURE_ELEVATION_CONTROL
} // end of three byte commands
if (serial0_buffer_index == 4) {
if ((command_string == "SA") & (serial0_buffer[2] > 47) && (serial0_buffer[2] < 53)){
serial_read_event_flag[serial0_buffer[2]-48] = 1;
command_good = 1;
Serial.println("OK");
}
if ((command_string == "SD") & (serial0_buffer[2] > 47) && (serial0_buffer[2] < 53)){
serial_read_event_flag[serial0_buffer[2]-48] = 0;
command_good = 1;
Serial.println("OK");
}
}
if (serial0_buffer_index == 5) {
if (command_string == "SW"){ // Serial Write command
switch (serial0_buffer[2]){
case '0': Serial.write(serial0_buffer[3]); command_good = 1; break;
#ifdef OPTION_SERIAL1_SUPPORT
case '1': Serial1.write(serial0_buffer[3]); command_good = 1; break;
#endif //OPTION_SERIAL1_SUPPORT
}
}
if (command_string == "DO"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
#ifdef DEBUG_SERVICE_SERIAL_BUFFER
Serial.print(F("service_serial_buffer: pin_value: "));
Serial.println(pin_value);
#endif //DEBUG_SERVICE_SERIAL_BUFFER
Serial.println("OK");
pinMode(pin_value,OUTPUT);
}
}
if (command_string == "DH"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
digitalWrite(pin_value,HIGH);
Serial.println("OK");
}
}
if (command_string == "DL"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
digitalWrite(pin_value,LOW);
Serial.println("OK");
}
}
if (command_string == "DI"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
pinMode(pin_value,INPUT);
Serial.println("OK");
}
}
if (command_string == "DP"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
//pinMode(pin_value,INPUT_PULLUP);
pinMode(pin_value,INPUT);
digitalWrite(pin_value,HIGH);
Serial.println("OK");
}
}
if (command_string == "DR"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
byte pin_read = digitalRead(pin_value);
Serial.print("DR");
Serial.write(serial0_buffer[2]);
Serial.write(serial0_buffer[3]);
if (pin_read){
Serial.println("1");
} else {
Serial.println("0");
}
}
}
if (command_string == "AR"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
int pin_read = analogRead(pin_value);
Serial.print("AR");
Serial.write(serial0_buffer[2]);
Serial.write(serial0_buffer[3]);
if (pin_read < 1000) {Serial.print("0");}
if (pin_read < 100) {Serial.print("0");}
if (pin_read < 10) {Serial.print("0");}
Serial.println(pin_read);
}
}
if (command_string == "NT"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
command_good = 1;
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
noTone(pin_value);
Serial.println("OK");
}
}
} //if (serial0_buffer_index == 5)
if (serial0_buffer_index == 8) {
if (command_string == "AW"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
int write_value = ((serial0_buffer[4]-48)*100) + ((serial0_buffer[5]-48)*10) + (serial0_buffer[6]-48);
if ((write_value >= 0) && (write_value < 256)){
analogWrite(pin_value,write_value);
Serial.println("OK");
command_good = 1;
}
}
}
}
if (serial0_buffer_index == 9) {
if (command_string == "DT"){
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58)){
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
int write_value = ((serial0_buffer[4]-48)*1000) + ((serial0_buffer[5]-48)*100) + ((serial0_buffer[6]-48)*10) + (serial0_buffer[7]-48);
if ((write_value >= 0) && (write_value <= 9999)){
tone(pin_value,write_value);
Serial.println("OK");
command_good = 1;
}
}
}
}
if (!command_good){Serial.println(F("ER02"));}
}
serial0_buffer_carriage_return_flag = 0;
serial0_buffer_index = 0;
} else {
if (((millis() - last_serial_receive_time) > REMOTE_BUFFER_TIMEOUT_MS) && serial0_buffer_index){
Serial.println(F("ER01"));
serial0_buffer_index = 0;
}
}
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
//--------------------------------------------------------------
void check_serial(){
if (Serial.available()) {
if (serial_led) {
digitalWrite(serial_led, HIGH); // blink the LED just to say we got something
}
incoming_serial_byte = Serial.read();
last_serial_receive_time = millis();
if ((incoming_serial_byte == 92) && (serial0_buffer_index == 0)) { // do we have a backslash command?
serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
serial0_buffer_index++;
backslash_command = 1;
return;
}
if (backslash_command) {
if (incoming_serial_byte == 13) { // do we have a carriage return?
switch(serial0_buffer[1]){
case 'D': if (debug_mode) {debug_mode = 0;} else {debug_mode = 1;} break; // D - Debug
case 'E' : // E - Initialize eeprom
initialize_eeprom_with_defaults();
Serial.println(F("Initialized eeprom, please reset..."));
break;
case 'L': // L - rotate to long path
if (azimuth < (180*HEADING_MULTIPLIER)){
submit_request(AZ,REQUEST_AZIMUTH,(azimuth+(180*HEADING_MULTIPLIER)));
} else {
submit_request(AZ,REQUEST_AZIMUTH,(azimuth-(180*HEADING_MULTIPLIER)));
}
break;
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
case 'R' :
Serial.print(F("Remote port rx sniff o"));
if (remote_port_rx_sniff){
remote_port_rx_sniff = 0;
Serial.println("ff");
} else {
remote_port_rx_sniff = 1;
Serial.println("n");
}
break;
case 'S':
for (int x = 2;x < serial0_buffer_index;x++){
Serial1.write(serial0_buffer[x]);
if (remote_port_tx_sniff){
Serial.write(serial0_buffer[x]);
}
}
Serial1.write(13);
if (remote_port_tx_sniff){
Serial.write(13);
}
break;
case 'T' :
Serial.print(F("Remote port tx sniff o"));
if (remote_port_tx_sniff){
remote_port_tx_sniff = 0;
Serial.println("ff");
} else {
remote_port_tx_sniff = 1;
Serial.println("n");
}
break;
case 'Z' :
Serial.print(F("Suspend auto remote commands o"));
if (suspend_remote_commands){
suspend_remote_commands = 0;
Serial.println("ff");
} else {
suspend_remote_commands = 1;
Serial.println("n");
}
break;
#endif //FEATURE_HOST_REMOTE_PROTOCOL
#ifdef FEATURE_ANCILLARY_PIN_CONTROL
case 'N' : // \Nxx - turn pin on; xx = pin number
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 4)){
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
pinMode(pin_value,OUTPUT);
digitalWrite(pin_value,HIGH);
Serial.println("OK");
} else {
Serial.println(F("Error"));
}
break;
case 'F' : // \Fxx - turn pin off; xx = pin number
if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 4)){
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
pinMode(pin_value,OUTPUT);
digitalWrite(pin_value,LOW);
Serial.println("OK");
} else {
Serial.println(F("Error"));
}
break;
case 'P' : // \Pxxyyy - turn on pin PWM; xx = pin number, yyy = PWM value (0-255)
if (((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 7)){
byte pin_value = 0;
if (toupper(serial0_buffer[2]) == 'A'){
pin_value = get_analog_pin(serial0_buffer[3]-48);
} else {
pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
}
int write_value = ((serial0_buffer[4]-48)*100) + ((serial0_buffer[5]-48)*10) + (serial0_buffer[6]-48);
if ((write_value >= 0) && (write_value < 256)){
pinMode(pin_value,OUTPUT);
analogWrite(pin_value,write_value);
Serial.println("OK");
} else {
Serial.println(F("Error"));
}
} else {
Serial.println(F("Error"));
}
break;
#endif //FEATURE_ANCILLARY_PIN_CONTROL
default: Serial.println(F("error"));
}
clear_command_buffer();
backslash_command = 0;
} else { // no, add the character to the buffer
if ((incoming_serial_byte > 96) && (incoming_serial_byte < 123)) {incoming_serial_byte = incoming_serial_byte - 32;} //uppercase it
if (incoming_serial_byte != 10) { // add it to the buffer if it's not a line feed
serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
serial0_buffer_index++;
}
}
} else {
#ifdef FEATURE_YAESU_EMULATION
yaesu_serial_command();
#endif //FEATURE_YAESU_EMULATION
#ifdef FEATURE_EASYCOM_EMULATION
easycom_serial_commmand();
#endif //FEATURE_EASYCOM_EMULATION
#ifdef FEATURE_REMOTE_UNIT_SLAVE
remote_unit_serial_command();
#endif //FEATURE_REMOTE_UNIT_SLAVE
}
if (serial_led) {
digitalWrite(serial_led, LOW);
}
} //if (Serial.available())
#ifdef OPTION_SERIAL1_SUPPORT
if (Serial1.available()){
incoming_serial_byte = Serial1.read();
#ifdef FEATURE_REMOTE_UNIT_SLAVE
if (serial_read_event_flag[1]){
Serial.print("EVS1");
Serial.write(incoming_serial_byte);
Serial.println();
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
if (remote_port_rx_sniff) {Serial.write(incoming_serial_byte);}
if ((incoming_serial_byte != 10) && (serial1_buffer_index < COMMAND_BUFFER_SIZE)){
//incoming_serial_byte = toupper(incoming_serial_byte);
serial1_buffer[serial1_buffer_index] = incoming_serial_byte;
serial1_buffer_index++;
if ((incoming_serial_byte == 13) || (serial1_buffer_index == COMMAND_BUFFER_SIZE)){
serial1_buffer_carriage_return_flag = 1;
}
}
serial1_last_receive_time = millis();
#endif //FEATURE_HOST_REMOTE_PROTOCOL
}
#endif //OPTION_SERIAL1_SUPPORT
#ifdef OPTION_SERIAL2_SUPPORT
if (Serial2.available()){
incoming_serial_byte = Serial2.read();
#ifdef FEATURE_REMOTE_UNIT_SLAVE
if (serial_read_event_flag[2]){
Serial.print("EVS1");
Serial.write(incoming_serial_byte);
Serial.println();
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
}
#endif //OPTION_SERIAL2_SUPPORT
#ifdef OPTION_SERIAL3_SUPPORT
if (Serial3.available()){
incoming_serial_byte = Serial3.read();
#ifdef FEATURE_REMOTE_UNIT_SLAVE
if (serial_read_event_flag[3]){
Serial.print("EVS3");
Serial.write(incoming_serial_byte);
Serial.println();
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
}
#endif //OPTION_SERIAL3_SUPPORT
#ifdef OPTION_SERIAL4_SUPPORT
if (Serial4.available()){
incoming_serial_byte = Serial4.read();
#ifdef FEATURE_REMOTE_UNIT_SLAVE
if (serial_read_event_flag[4]){
Serial.print("EVS4");
Serial.write(incoming_serial_byte);
Serial.println();
}
#endif //FEATURE_REMOTE_UNIT_SLAVE
}
#endif //OPTION_SERIAL4_SUPPORT
}
//--------------------------------------------------------------
void check_buttons(){
#ifdef FEATURE_ADAFRUIT_BUTTONS
int buttons = 0;
buttons = lcd.readButtons();
if (buttons & BUTTON_RIGHT) {
#else
if (button_cw && (digitalRead(button_cw) == LOW)) {
#endif //FEATURE_ADAFRUIT_BUTTONS
if (azimuth_button_was_pushed == 0) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {Serial.println(F("check_buttons: button_cw pushed"));}
#endif //DEBUG_BUTTONS
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
if (raw_azimuth < (AZ_MANUAL_ROTATE_CW_LIMIT*HEADING_MULTIPLIER)) {
#endif
submit_request(AZ,REQUEST_CW,0);
azimuth_button_was_pushed = 1;
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
} else {
#ifdef DEBUG_BUTTONS
if (debug_mode) {Serial.println(F("check_buttons: exceeded AZ_MANUAL_ROTATE_CW_LIMIT"));}
#endif //DEBUG_BUTTONS
}
#endif
}
} else {
#ifdef FEATURE_ADAFRUIT_BUTTONS
if (buttons & BUTTON_LEFT) {
#else
if (button_ccw && (digitalRead(button_ccw) == LOW)) {
#endif //FEATURE_ADAFRUIT_BUTTONS
if (azimuth_button_was_pushed == 0) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: button_ccw pushed"));
}
#endif //DEBUG_BUTTONS
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
if (raw_azimuth > (AZ_MANUAL_ROTATE_CCW_LIMIT*HEADING_MULTIPLIER)) {
#endif
submit_request(AZ,REQUEST_CCW,0);
azimuth_button_was_pushed = 1;
#ifdef OPTION_AZ_MANUAL_ROTATE_LIMITS
} else {
#ifdef DEBUG_BUTTONS
if (debug_mode) {Serial.println(F("check_buttons: exceeded AZ_MANUAL_ROTATE_CCW_LIMIT"));}
#endif //DEBUG_BUTTONS
}
#endif //OPTION_AZ_MANUAL_ROTATE_LIMITS
}
}
}
#ifdef FEATURE_ADAFRUIT_BUTTONS
if ((azimuth_button_was_pushed) && (!(buttons & 0x12))) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: no button depressed"));
}
#endif // DEBUG_BUTTONS
submit_request(AZ,REQUEST_STOP,0);
azimuth_button_was_pushed = 0;
}
#else
if ((azimuth_button_was_pushed) && (digitalRead(button_ccw) == HIGH) && (digitalRead(button_cw) == HIGH)) {
delay(200);
if ((digitalRead(button_ccw) == HIGH) && (digitalRead(button_cw) == HIGH)) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: no AZ button depressed"));
}
#endif // DEBUG_BUTTONS
submit_request(AZ,REQUEST_STOP,0);
azimuth_button_was_pushed = 0;
}
}
#endif //FEATURE_ADAFRUIT_BUTTONS
#ifdef FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_ADAFRUIT_BUTTONS
if (buttons & 0x08) {
#else
if (button_up && (digitalRead(button_up) == LOW)) {
#endif //FEATURE_ADAFRUIT_BUTTONS
if (elevation_button_was_pushed == 0) {
submit_request(EL,REQUEST_UP,0);
elevation_button_was_pushed = 1;
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: button_up pushed"));
}
#endif //DEBUG_BUTTONS
}
} else {
#ifdef FEATURE_ADAFRUIT_BUTTONS
if (buttons & 0x04) {
#else
if (button_down && (digitalRead(button_down) == LOW)) {
#endif //FEATURE_ADAFRUIT_BUTTONS
if (elevation_button_was_pushed == 0) {
submit_request(EL,REQUEST_DOWN,0);
elevation_button_was_pushed = 1;
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: button_down pushed"));
}
#endif //DEBUG_BUTTONS
}
}
}
#ifdef FEATURE_ADAFRUIT_BUTTONS
if ((elevation_button_was_pushed) && (!(buttons & 0x0C))) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: no EL button depressed"));
}
#endif // DEBUG_BUTTONS
submit_request(EL,REQUEST_STOP,0);
elevation_button_was_pushed = 0;
}
#else
if ((elevation_button_was_pushed) && (digitalRead(button_up) == HIGH) && (digitalRead(button_down) == HIGH)) {
delay(200);
if ((digitalRead(button_up) == HIGH) && (digitalRead(button_down) == HIGH)) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: no EL button depressed"));
}
#endif // DEBUG_BUTTONS
submit_request(EL,REQUEST_STOP,0);
elevation_button_was_pushed = 0;
}
}
#endif //FEATURE_ADAFRUIT_BUTTONS
#endif //FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_PARK
static byte park_button_pushed = 0;
static unsigned long last_time_park_button_pushed = 0;
if (button_park){
if ((digitalRead(button_park) == LOW)){
park_button_pushed = 1;
last_time_park_button_pushed = millis();
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: button_park pushed"));
}
#endif //DEBUG_BUTTONS
} else {
if ((park_button_pushed) && ((millis() - last_time_park_button_pushed) >= 250)){
#ifdef DEBUG_BUTTONS
if (debug_mode) {
Serial.println(F("check_buttons: executing park"));
}
#endif //DEBUG_BUTTONS
submit_request(AZ,REQUEST_AZIMUTH_RAW,PARK_AZIMUTH);
#ifdef FEATURE_ELEVATION_CONTROL
submit_request(EL,REQUEST_ELEVATION,PARK_ELEVATION);
#endif // FEATURE_ELEVATION
park_button_pushed = 0;
}
}
}
#endif
if (button_stop) {
if ((digitalRead(button_stop) == LOW)) {
#ifdef DEBUG_BUTTONS
if (debug_mode) {Serial.println(F("check_buttons: button_stop pushed"));}
#endif //DEBUG_BUTTONS
submit_request(AZ,REQUEST_STOP,0);
#ifdef FEATURE_ELEVATION_CONTROL
submit_request(EL,REQUEST_STOP,0);
#endif //FEATURE_ELEVATION_CONTROL
}
}
}
//--------------------------------------------------------------
#ifdef FEATURE_LCD_DISPLAY
char *azimuth_direction(int azimuth_in){
azimuth_in = azimuth_in / HEADING_MULTIPLIER;
if (azimuth_in > 348) {return "N";}
if (azimuth_in > 326) {return "NNW";}
if (azimuth_in > 303) {return "NW";}
if (azimuth_in > 281) {return "WNW";}
if (azimuth_in > 258) {return "W";}
if (azimuth_in > 236) {return "WSW";}
if (azimuth_in > 213) {return "SW";}
if (azimuth_in > 191) {return "SSW";}
if (azimuth_in > 168) {return "S";}
if (azimuth_in > 146) {return "SSE";}
if (azimuth_in > 123) {return "SE";}
if (azimuth_in > 101) {return "ESE";}
if (azimuth_in > 78) {return "E";}
if (azimuth_in > 56) {return "ENE";}
if (azimuth_in > 33) {return "NE";}
if (azimuth_in > 11) {return "NNE";}
return "N";
}
#endif
//--------------------------------------------------------------
#ifdef FEATURE_LCD_DISPLAY
void update_display()
{
// update the LCD display
static byte lcd_state_row_0 = 0;
static byte lcd_state_row_1 = 0;
String direction_string;
static int last_azimuth = -1;
char workstring[7];
unsigned int target = 0;
#ifdef FEATURE_ELEVATION_CONTROL
static int last_elevation = -1;
static int last_target_elevation = 0;
#endif
// row 0 ------------------------------------------------------------
if (((millis() - last_lcd_update) > LCD_UPDATE_TIME) || (push_lcd_update)){
if ((lcd_state_row_0 == 0) && (lcd_state_row_1 == 0)){
lcd.clear();
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_DIRECTION;
}
#ifndef FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_AZ_PRESET_ENCODER
target = az_encoder_raw_degrees;
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (preset_encoders_state == ENCODER_AZ_PENDING) {
clear_display_row(0); // Show Target Deg on upper line
direction_string = "Target ";
dtostrf(target/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_TARGET_AZ;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
} else {
#endif //FEATURE_AZ_PRESET_ENCODER
if (az_state != IDLE) {
if (az_request_queue_state == IN_PROGRESS_TO_TARGET) {
clear_display_row(0);
direction_string = "Rotating to ";
dtostrf(target_azimuth/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
//direction_string.concat(int(target_azimuth / LCD_HEADING_MULTIPLIER));
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_TO;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
} else {
if ((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) {
if (lcd_state_row_0 != LCD_ROTATING_CW) {
clear_display_row(0);
direction_string = "Rotating CW";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_CW;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
}
} else {
if (lcd_state_row_0 != LCD_ROTATING_CCW) {
clear_display_row(0);
direction_string = "Rotating CCW";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_CCW;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
}
}
}
} else { // az_state == IDLE
if ((last_azimuth != azimuth) || (lcd_state_row_0 != LCD_DIRECTION)){
direction_string = azimuth_direction(azimuth);
if ((last_direction_string == direction_string) || (lcd_state_row_0 != LCD_DIRECTION)) {
clear_display_row(0);
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_DIRECTION;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
} else {
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2)-1,0);
lcd.print(" ");
lcd.print(direction_string);
lcd.print(" ");
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
}
}
} //(az_state != IDLE)
#ifdef FEATURE_AZ_PRESET_ENCODER
} //(preset_encoders_state == ENCODER_AZ_PENDING)
#endif //FEATURE_AZ_PRESET_ENCODER
#endif
// ------------ AZ & EL -----------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_AZ_PRESET_ENCODER
#ifndef FEATURE_EL_PRESET_ENCODER
unsigned int target = az_encoder_raw_degrees;
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (preset_encoders_state == ENCODER_AZ_PENDING) {
clear_display_row(0); // Show Target Deg on upper line
direction_string = "Target ";
dtostrf(target/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_TARGET_AZ;
#ifdef DEBUG_DISPLAY
if (debug_mode) {
Serial.print(F("update_display: "));
Serial.println(direction_string);
}
#endif //DEBUG_DISPLAY
} else {
#endif //ndef FEATURE_EL_PRESET_ENCODER
#endif //FEATURE_AZ_PRESET_ENCODER
#ifdef FEATURE_EL_PRESET_ENCODER
unsigned int target = az_encoder_raw_degrees;
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (target > (359*LCD_HEADING_MULTIPLIER)) {target = target - (360*LCD_HEADING_MULTIPLIER);}
if (preset_encoders_state != ENCODER_IDLE){
switch(preset_encoders_state){
case ENCODER_AZ_PENDING:
clear_display_row(0); // Show Target Deg on upper line
direction_string = "Az Target ";
dtostrf(target/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_TARGET_AZ;
break;
case ENCODER_EL_PENDING:
clear_display_row(0); // Show Target Deg on upper line
direction_string = "El Target ";
dtostrf(el_encoder_degrees/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_TARGET_EL;
break;
case ENCODER_AZ_EL_PENDING:
clear_display_row(0); // Show Target Deg on upper line
direction_string = "Target ";
dtostrf(target/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
dtostrf(el_encoder_degrees/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(" ");
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_TARGET_AZ_EL;
break;
}
} else { //(preset_encoders_state != ENCODER_IDLE)
#endif //FEATURE_EL_PRESET_ENCODER
if ((az_state != IDLE) && (el_state == IDLE)) {
if (az_request_queue_state == IN_PROGRESS_TO_TARGET) {
clear_display_row(0);
direction_string = "Rotating to ";
dtostrf(target_azimuth/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_TO;
} else {
if ((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) {
clear_display_row(0);
direction_string = "Rotating CW";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_CW;
} else {
clear_display_row(0);
direction_string = "Rotating CCW";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ROTATING_CCW;
}
}
} //((az_state != IDLE) && (el_state == IDLE))
if ((az_state == IDLE) && (el_state != IDLE)) {
if ((el_request_queue_state == IN_PROGRESS_TO_TARGET) && ((lcd_state_row_0 != LCD_ELEVATING_TO) || (target_elevation != last_target_elevation))){
clear_display_row(0);
direction_string = "Elevating to ";
dtostrf(target_elevation/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ELEVATING_TO;
} else {
if (((el_state == SLOW_START_UP)||(el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (lcd_state_row_0 != LCD_ELEVATING_UP)){
clear_display_row(0);
direction_string = "Elevating Up";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ELEVATING_UP;
}
if (((el_state == SLOW_START_DOWN)||(el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) && (lcd_state_row_0 != LCD_ELEVATING_DOWN)) {
clear_display_row(0);
direction_string = "Elevating Down";
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_ELEVATING_DOWN;
}
}
} //((az_state == IDLE) && (el_state != IDLE))
if ((az_state != IDLE) && (el_state != IDLE) && (lcd_state_row_0 != LCD_ROTATING_AZ_EL)) {
clear_display_row(0);
direction_string = "Rotating ";
if (az_request_queue_state == NONE) {
if (current_az_state() == ROTATING_CW) {
direction_string.concat("CW");
} else {
direction_string.concat("CCW");
}
} else {
direction_string.concat(int(target_azimuth / LCD_HEADING_MULTIPLIER));
}
direction_string.concat(" ");
if (el_request_queue_state == NONE) {
if (current_el_state() == ROTATING_UP) {
direction_string.concat("UP");
} else {
direction_string.concat("DOWN");
}
} else {
dtostrf(target_elevation/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
}
lcd_state_row_0 = LCD_ROTATING_AZ_EL;
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2)-1,0);
lcd.print(direction_string);
} //((az_state != IDLE) && (el_state != IDLE))
if ((az_state == IDLE) && (el_state == IDLE)) {
if ((last_azimuth != azimuth) || (lcd_state_row_0 != LCD_DIRECTION)){
direction_string = azimuth_direction(azimuth);
if ((last_direction_string == direction_string) || (lcd_state_row_0 != LCD_DIRECTION)) {
clear_display_row(0);
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
lcd.print(direction_string);
lcd_state_row_0 = LCD_DIRECTION;
} else {
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2)-1,0);
lcd.print(" ");
lcd.print(direction_string);
lcd.print(" ");
}
}
} //((az_state == IDLE) && (el_state == IDLE))
#ifdef FEATURE_EL_PRESET_ENCODER
} //(preset_encoders_state != ENCODER_IDLE)
#endif //FEATURE_EL_PRESET_ENCODER
#ifdef FEATURE_AZ_PRESET_ENCODER
#ifndef FEATURE_EL_PRESET_ENCODER
}
#endif //ndef FEATURE_EL_PRESET_ENCODER
#endif //FEATURE_AZ_PRESET_ENCODER
#endif //FEATURE_ELEVATION_CONTROL
push_lcd_update = 0;
}
// row 1 --------------------------------------------
if ((millis()-last_lcd_update) > LCD_UPDATE_TIME) {
#ifndef FEATURE_ELEVATION_CONTROL //---------------- az only -----------------------------------
if (last_azimuth != azimuth) {
clear_display_row(1);
direction_string = "Azimuth ";
dtostrf(azimuth/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
direction_string.concat(char(223));
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),1);
lcd.print(direction_string);
last_azimuth = azimuth;
lcd_state_row_1 = LCD_HEADING;
}
#endif //FEATURE_ELEVATION_CONTROL---------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL //--------------------az & el---------------------------------
if ((last_azimuth != azimuth) || (last_elevation != elevation)){
clear_display_row(1);
#ifdef FEATURE_ONE_DECIMAL_PLACE_HEADINGS
if ((azimuth >= 1000) && (elevation >= 1000)){
direction_string = "Az";
} else {
direction_string = "Az ";
}
#else
direction_string = "Az ";
#endif //FEATURE_ONE_DECIMAL_PLACE_HEADINGS
dtostrf(azimuth/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
#ifndef FEATURE_ONE_DECIMAL_PLACE_HEADINGS
if (LCD_COLUMNS > 14) {direction_string.concat(char(223));}
#else
if ((LCD_COLUMNS > 18) || ((azimuth < 100) && (elevation < 100))) {direction_string.concat(char(223));}
#endif
#ifdef FEATURE_ONE_DECIMAL_PLACE_HEADINGS
if ((elevation >= 1000) && (azimuth >= 1000)){
direction_string.concat(" El");
} else {
direction_string.concat(" El ");
}
#else
direction_string.concat(" El ");
#endif //FEATURE_ONE_DECIMAL_PLACE_HEADINGS
dtostrf(elevation/LCD_HEADING_MULTIPLIER,1,LCD_DECIMAL_PLACES,workstring);
direction_string.concat(workstring);
#ifndef FEATURE_ONE_DECIMAL_PLACE_HEADINGS
if (LCD_COLUMNS > 14) {direction_string.concat(char(223));}
#else
if ((LCD_COLUMNS > 18) || ((azimuth < 100) && (elevation < 100))) {direction_string.concat(char(223));}
#endif
lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),1);
lcd.print(direction_string);
last_azimuth = azimuth;
last_elevation = elevation;
lcd_state_row_1 = LCD_HEADING;
}
#endif //FEATURE_ELEVATION_CONTROL //------------------------------------------------------------
}
if ((millis() - last_lcd_update) > LCD_UPDATE_TIME) {last_lcd_update = millis();}
last_direction_string = direction_string;
}
#endif
//--------------------------------------------------------------
#ifdef FEATURE_LCD_DISPLAY
void clear_display_row(byte row_number)
{
lcd.setCursor(0,row_number);
for (byte x = 0; x < LCD_COLUMNS; x++) {
lcd.print(" ");
}
}
#endif
//--------------------------------------------------------------
void get_keystroke()
{
while (Serial.available() == 0) {}
while (Serial.available() > 0) {
incoming_serial_byte = Serial.read();
}
}
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void yaesu_x_command() {
if (serial0_buffer_index > 1) {
switch (serial0_buffer[1]) {
case '4':
normal_az_speed_voltage = PWM_SPEED_VOLTAGE_X4;
update_az_variable_outputs(PWM_SPEED_VOLTAGE_X4);
#if defined(FEATURE_ELEVATION_CONTROL) && defined(OPTION_EL_SPEED_FOLLOWS_AZ_SPEED)
normal_el_speed_voltage = PWM_SPEED_VOLTAGE_X4;
update_el_variable_outputs(PWM_SPEED_VOLTAGE_X4);
#endif
Serial.print(F("Speed X4\r\n"));
break;
case '3':
normal_az_speed_voltage = PWM_SPEED_VOLTAGE_X3;
update_az_variable_outputs(PWM_SPEED_VOLTAGE_X3);
#if defined(FEATURE_ELEVATION_CONTROL) && defined(OPTION_EL_SPEED_FOLLOWS_AZ_SPEED)
normal_el_speed_voltage = PWM_SPEED_VOLTAGE_X3;
update_el_variable_outputs(PWM_SPEED_VOLTAGE_X3);
#endif
Serial.print(F("Speed X3\r\n"));
break;
case '2':
normal_az_speed_voltage = PWM_SPEED_VOLTAGE_X2;
update_az_variable_outputs(PWM_SPEED_VOLTAGE_X2);
#if defined(FEATURE_ELEVATION_CONTROL) && defined(OPTION_EL_SPEED_FOLLOWS_AZ_SPEED)
normal_el_speed_voltage = PWM_SPEED_VOLTAGE_X2;
update_el_variable_outputs(PWM_SPEED_VOLTAGE_X2);
#endif
Serial.print(F("Speed X2\r\n"));
break;
case '1':
normal_az_speed_voltage = PWM_SPEED_VOLTAGE_X1;
update_az_variable_outputs(PWM_SPEED_VOLTAGE_X1);
#if defined(FEATURE_ELEVATION_CONTROL) && defined(OPTION_EL_SPEED_FOLLOWS_AZ_SPEED)
normal_el_speed_voltage = PWM_SPEED_VOLTAGE_X1;
update_el_variable_outputs(PWM_SPEED_VOLTAGE_X1);
#endif
Serial.print(F("Speed X1\r\n"));
break;
default: Serial.println(F("?>")); break;
}
} else {
Serial.println(F("?>"));
}
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
#ifdef OPTION_GS_232B_EMULATION
void yaesu_p_command()
{
if ((serial0_buffer[1] == '3') && (serial0_buffer_index > 2)) { // P36 command
configuration.azimuth_rotation_capability = 360;
Serial.print(F("Mode 360 degree\r\n"));
write_settings_to_eeprom();
} else {
if ((serial0_buffer[1] == '4') && (serial0_buffer_index > 2)) { // P45 command
configuration.azimuth_rotation_capability = 450;
Serial.print(F("Mode 450 degree\r\n"));
write_settings_to_eeprom();
} else {
Serial.println(F("?>"));
}
}
}
#endif //OPTION_GS_232B_EMULATION
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void yaesu_o_command()
{
#ifdef FEATURE_ELEVATION_CONTROL
if ((serial0_buffer[1] == '2') && (serial0_buffer_index > 1)) { // did we get the O2 command?
yaesu_o2_command();
return;
}
#endif
clear_serial_buffer();
Serial.println(F("Rotate to full CCW and send keystroke..."));
get_keystroke();
read_azimuth();
configuration.analog_az_full_ccw = analog_az;
write_settings_to_eeprom();
print_wrote_to_memory();
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void print_wrote_to_memory(){
Serial.println(F("Wrote to memory"));
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void clear_serial_buffer(){
delay(200);
while (Serial.available()) {incoming_serial_byte = Serial.read();}
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#ifdef FEATURE_YAESU_EMULATION
void yaesu_f_command()
{
#ifdef FEATURE_ELEVATION_CONTROL
if ((serial0_buffer[1] == '2') && (serial0_buffer_index > 1)) { // did we get the F2 command?
yaesu_f2_command();
return;
}
#endif
clear_serial_buffer();
Serial.println(F("Rotate to full CW and send keystroke..."));
get_keystroke();
read_azimuth();
configuration.analog_az_full_cw = analog_az;
write_settings_to_eeprom();
print_wrote_to_memory();
}
#endif //FEATURE_YAESU_EMULATION
//--------------------------------------------------------------
#if defined(FEATURE_YAESU_EMULATION) && defined(FEATURE_ELEVATION_CONTROL)
void yaesu_o2_command()
{
clear_serial_buffer();
Serial.println(F("Elevate to 0 degrees and send keystroke..."));
get_keystroke();
read_elevation();
configuration.analog_el_0_degrees = analog_el;
write_settings_to_eeprom();
print_wrote_to_memory();
}
#endif //defined(FEATURE_YAESU_EMULATION) && defined(FEATURE_ELEVATION_CONTROL)
//--------------------------------------------------------------
#if defined(FEATURE_YAESU_EMULATION) && defined(FEATURE_ELEVATION_CONTROL)
void yaesu_f2_command()
{
clear_serial_buffer();
Serial.println(F("Elevate to 180 (or max elevation) and send keystroke..."));
get_keystroke();
read_elevation();
configuration.analog_el_max_elevation = analog_el;
write_settings_to_eeprom();
print_wrote_to_memory();
}
#endif //defined(FEATURE_YAESU_EMULATION) && defined(FEATURE_ELEVATION_CONTROL)
//--------------------------------------------------------------
void read_settings_from_eeprom()
{
//EEPROM_readAnything(0,configuration);
byte* p = (byte*)(void*)&configuration;
unsigned int i;
int ee = 0;
for (i = 0; i < sizeof(configuration); i++){
*p++ = EEPROM.read(ee++);
}
if (configuration.magic_number == EEPROM_MAGIC_NUMBER) {
#ifdef DEBUG_EEPROM
if (debug_mode) {
Serial.print(F("read_settings_from_eeprom: reading settings from eeprom: "));
Serial.print("analog_az_full_ccw");
Serial.println(configuration.analog_az_full_ccw,DEC);
Serial.print("analog_az_full_cw");
Serial.println(configuration.analog_az_full_cw,DEC);
Serial.print("analog_el_0_degrees");
Serial.println(configuration.analog_el_0_degrees,DEC);
Serial.print("analog_el_max_elevation");
Serial.println(configuration.analog_el_max_elevation,DEC);
Serial.print("azimuth_starting_point");
Serial.println(configuration.azimuth_starting_point,DEC);
Serial.print("azimuth_rotation_capability");
Serial.println(configuration.azimuth_rotation_capability,DEC);
Serial.print("last_azimuth:");
Serial.println(configuration.last_azimuth,1);
Serial.print("last_elevation");
Serial.println(configuration.last_elevation,1);
}
#endif //DEBUG_EEPROM
#ifdef FEATURE_AZ_POSITION_ROTARY_ENCODER
raw_azimuth = int(configuration.last_azimuth*HEADING_MULTIPLIER);
if (raw_azimuth >= (360*HEADING_MULTIPLIER)){
azimuth = raw_azimuth - (360*HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
#endif //FEATURE_AZ_POSITION_ROTARY_ENCODER
#ifdef FEATURE_EL_POSITION_ROTARY_ENCODER
elevation = int(configuration.last_elevation*HEADING_MULTIPLIER);
#endif //FEATURE_EL_POSITION_ROTARY_ENCODER
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
raw_azimuth = int(configuration.last_azimuth*HEADING_MULTIPLIER);
if (raw_azimuth >= (360*HEADING_MULTIPLIER)){
azimuth = raw_azimuth - (360*HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
az_position_pulse_input_azimuth = configuration.last_azimuth;
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
elevation = int(configuration.last_elevation*HEADING_MULTIPLIER);
el_position_pulse_input_elevation = configuration.last_elevation;
#endif //FEATURE_EL_POSITION_PULSE_INPUT
// #ifdef FEATURE_AZ_POSITION_PULSE_INPUT
// volatile float az_position_pulse_azimuth = 0;
// #endif //FEATURE_AZ_POSITION_PULSE_INPUT a
} else { // initialize eeprom with default values
#ifdef DEBUG_EEPROM
if (debug_mode) {
Serial.println(F("read_settings_from_eeprom: uninitialized eeprom, calling initialize_eeprom_with_defaults()"));
}
#endif //DEBUG_EEPROM
initialize_eeprom_with_defaults();
}
}
//--------------------------------------------------------------
void initialize_eeprom_with_defaults(){
#ifdef DEBUG_EEPROM
if (debug_mode) {
Serial.println(F("initialize_eeprom_with_defaults: writing eeprom"));
}
#endif //DEBUG_EEPROM
configuration.analog_az_full_ccw = ANALOG_AZ_FULL_CCW;
configuration.analog_az_full_cw = ANALOG_AZ_FULL_CW;
configuration.analog_el_0_degrees = ANALOG_EL_0_DEGREES;
configuration.analog_el_max_elevation = ANALOG_EL_MAX_ELEVATION;
configuration.azimuth_starting_point = AZIMUTH_STARTING_POINT_DEFAULT;
configuration.azimuth_rotation_capability = AZIMUTH_ROTATION_CAPABILITY_DEFAULT;
configuration.last_azimuth = raw_azimuth;
#ifdef FEATURE_ELEVATION_CONTROL
configuration.last_elevation = elevation;
#else
configuration.last_elevation = 0;
#endif
write_settings_to_eeprom();
}
//--------------------------------------------------------------
void write_settings_to_eeprom()
{
#ifdef DEBUG_EEPROM
if (debug_mode) {
Serial.print(F("write_settings_to_eeprom: writing settings to eeprom\n"));
}
#endif //DEBUG_EEPROM
configuration.magic_number = EEPROM_MAGIC_NUMBER;
const byte* p = (const byte*)(const void*)&configuration;
unsigned int i;
int ee = 0;
for (i = 0; i < sizeof(configuration); i++){
EEPROM.write(ee++, *p++);
}
//EEPROM_writeAnything(0,configuration);
configuration_dirty = 0;
}
//--------------------------------------------------------------
void az_check_operation_timeout()
{
// check if the last executed rotation operation has been going on too long
if (((millis() - az_last_rotate_initiation) > OPERATION_TIMEOUT) && (az_state != IDLE)) {
submit_request(AZ,REQUEST_KILL,0);
#ifdef DEBUG_AZ_CHECK_OPERATION_TIMEOUT
if (debug_mode) {Serial.println(F("az_check_operation_timeout: timeout reached, aborting rotation"));}
#endif //DEBUG_AZ_CHECK_OPERATION_TIMEOUT
}
}
//--------------------------------------------------------------
#ifdef FEATURE_TIMED_BUFFER
void clear_timed_buffer()
{
timed_buffer_status = EMPTY;
timed_buffer_number_entries_loaded = 0;
timed_buffer_entry_pointer = 0;
}
#endif //FEATURE_TIMED_BUFFER
//--------------------------------------------------------------
void yaesu_m_command(){
int parsed_azimuth = 0;
// parse out M command
if (serial0_buffer_index > 4) { // if there are more than 4 characters in the command buffer, we got a timed interval command
#ifdef FEATURE_TIMED_BUFFER
yaesu_az_load_timed_intervals();
#else
Serial.println(F("Feature not activated ?>"));
#endif //FEATURE_TIMED_BUFFER
return;
} else { // if there are four characters, this is just a single direction setting
if (serial0_buffer_index == 4){
parsed_azimuth = ((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48);
#ifdef FEATURE_TIMED_BUFFER
clear_timed_buffer();
#endif //FEATURE_TIMED_BUFFER
if ((parsed_azimuth > -1) && (parsed_azimuth <= (configuration.azimuth_starting_point + configuration.azimuth_rotation_capability))) {
submit_request(AZ,REQUEST_AZIMUTH,(parsed_azimuth*HEADING_MULTIPLIER));
return;
}
}
}
Serial.println(F("?>"));
}
//--------------------------------------------------------------
#ifdef FEATURE_TIMED_BUFFER
void initiate_timed_buffer()
{
if (timed_buffer_status == LOADED_AZIMUTHS) {
timed_buffer_status = RUNNING_AZIMUTHS;
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[1]);
last_timed_buffer_action_time = millis();
timed_buffer_entry_pointer = 2;
#ifdef DEBUG_TIMED_BUFFER
if (debug_mode) {Serial.println(F("initiate_timed_buffer: changing state to RUNNING_AZIMUTHS"));}
#endif //DEBUG_TIMED_BUFFER
} else {
#ifdef FEATURE_ELEVATION_CONTROL
if (timed_buffer_status == LOADED_AZIMUTHS_ELEVATIONS) {
timed_buffer_status = RUNNING_AZIMUTHS_ELEVATIONS;
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[1]);
submit_request(EL,REQUEST_ELEVATION,timed_buffer_elevations[1]);
last_timed_buffer_action_time = millis();
timed_buffer_entry_pointer = 2;
#ifdef DEBUG_TIMED_BUFFER
if (debug_mode) {Serial.println(F("initiate_timed_buffer: changing state to RUNNING_AZIMUTHS_ELEVATIONS"));}
#endif //DEBUG_TIMED_BUFFER
} else {
Serial.println(">"); // error
}
#endif
}
}
#endif //FEATURE_TIMED_BUFFER
//--------------------------------------------------------------
#ifdef FEATURE_TIMED_BUFFER
void print_timed_buffer_empty_message(){
#ifdef DEBUG_TIMED_BUFFER
if (debug_mode) {Serial.println(F("check_timed_interval: completed timed buffer; changing state to EMPTY"));}
#endif //DEBUG_TIMED_BUFFER
}
#endif //FEATURE_TIMED_BUFFER
//--------------------------------------------------------------
#ifdef FEATURE_TIMED_BUFFER
void check_timed_interval()
{
if ((timed_buffer_status == RUNNING_AZIMUTHS) && (((millis() - last_timed_buffer_action_time)/1000) > timed_buffer_interval_value_seconds)) {
timed_buffer_entry_pointer++;
#ifdef DEBUG_TIMED_BUFFER
if (debug_mode) {Serial.println(F("check_timed_interval: executing next timed interval step - azimuths"));}
#endif //DEBUG_TIMED_BUFFER
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[timed_buffer_entry_pointer-1]);
last_timed_buffer_action_time = millis();
if (timed_buffer_entry_pointer == timed_buffer_number_entries_loaded) {
clear_timed_buffer();
print_timed_buffer_empty_message();
}
}
#ifdef FEATURE_ELEVATION_CONTROL
if ((timed_buffer_status == RUNNING_AZIMUTHS_ELEVATIONS) && (((millis() - last_timed_buffer_action_time)/1000) > timed_buffer_interval_value_seconds)) {
timed_buffer_entry_pointer++;
#ifdef DEBUG_TIMED_BUFFER
if (debug_mode) {Serial.println(F("check_timed_interval: executing next timed interval step - az and el"));}
#endif //DEBUG_TIMED_BUFFER
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[timed_buffer_entry_pointer-1]);
submit_request(EL,REQUEST_ELEVATION,timed_buffer_elevations[timed_buffer_entry_pointer-1]);
last_timed_buffer_action_time = millis();
if (timed_buffer_entry_pointer == timed_buffer_number_entries_loaded) {
clear_timed_buffer();
print_timed_buffer_empty_message();
}
}
#endif
}
#endif //FEATURE_TIMED_BUFFER
//--------------------------------------------------------------
#ifdef FEATURE_TIMED_BUFFER
void yaesu_az_load_timed_intervals()
{
int parsed_value = 0;
clear_timed_buffer();
parsed_value = ((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48);
if ((parsed_value > 0) && (parsed_value < 1000)) {
timed_buffer_interval_value_seconds = parsed_value;
for (int x = 5; x < serial0_buffer_index; x = x + 4) {
parsed_value = ((int(serial0_buffer[x])-48)*100) + ((int(serial0_buffer[x+1])-48)*10) + (int(serial0_buffer[x+2])-48);
if ((parsed_value > -1) && (parsed_value < 361)) { // is it a valid azimuth?
timed_buffer_azimuths[timed_buffer_number_entries_loaded] = parsed_value * HEADING_MULTIPLIER;
timed_buffer_number_entries_loaded++;
timed_buffer_status = LOADED_AZIMUTHS;
if (timed_buffer_number_entries_loaded > TIMED_INTERVAL_ARRAY_SIZE) { // is the array full?
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[0]); // array is full, go to the first azimuth
timed_buffer_entry_pointer = 1;
return;
}
} else { // we hit an invalid bearing
timed_buffer_status = EMPTY;
timed_buffer_number_entries_loaded = 0;
Serial.println(F("?>")); // error
return;
}
}
submit_request(AZ,REQUEST_AZIMUTH,timed_buffer_azimuths[0]); // go to the first azimuth
timed_buffer_entry_pointer = 1;
} else {
Serial.println(F("?>")); // error
}
}
#endif //FEATURE_TIMED_BUFFER
//--------------------------------------------------------------
void read_azimuth(){
unsigned int previous_raw_azimuth = raw_azimuth;
static unsigned long last_measurement_time = 0;
#ifdef DEBUG_HEADING_READING_TIME
static unsigned long last_time = 0;
static unsigned long last_print_time = 0;
static float average_read_time = 0;
#endif //DEBUG_HEADING_READING_TIME
#ifndef FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
if ((millis() - last_measurement_time) > AZIMUTH_MEASUREMENT_FREQUENCY_MS){
#else
if (1){
#endif
#ifdef FEATURE_AZ_POSITION_POTENTIOMETER
// read analog input and convert it to degrees; this gets funky because of 450 degree rotation
// Bearings: 180-------359-0--------270
// Voltage: 0----------------------5
analog_az = analogRead(rotator_analog_az);
raw_azimuth = (map(analog_az, configuration.analog_az_full_ccw, configuration.analog_az_full_cw, (configuration.azimuth_starting_point*HEADING_MULTIPLIER), ((configuration.azimuth_starting_point + configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER)));
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
if (AZIMUTH_SMOOTHING_FACTOR > 0) {
raw_azimuth = (raw_azimuth*(1-(AZIMUTH_SMOOTHING_FACTOR/100))) + (previous_raw_azimuth*(AZIMUTH_SMOOTHING_FACTOR/100));
}
if (raw_azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = raw_azimuth - (360 * HEADING_MULTIPLIER);
if (azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = azimuth - (360 * HEADING_MULTIPLIER);
}
} else {
if (raw_azimuth < 0) {
azimuth = raw_azimuth + (360 * HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
}
#endif //FEATURE_AZ_POSITION_POTENTIOMETER
#ifdef FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
static unsigned long last_remote_unit_az_query_time = 0;
// do we have a command result waiting for us?
if (remote_unit_command_results_available == REMOTE_UNIT_AZ_COMMAND) {
#ifdef DEBUG_HEADING_READING_TIME
average_read_time = (average_read_time + (millis()-last_time))/2.0;
last_time = millis();
if (debug_mode){
if ((millis()-last_print_time) > 1000){
Serial.print(F("read_azimuth: avg read frequency: "));
Serial.println(average_read_time,2);
last_print_time = millis();
}
}
#endif //DEBUG_HEADING_READING_TIME
raw_azimuth = remote_unit_command_result_float * HEADING_MULTIPLIER;
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
if (AZIMUTH_SMOOTHING_FACTOR > 0) {
raw_azimuth = (raw_azimuth*(1-(AZIMUTH_SMOOTHING_FACTOR/100))) + (previous_raw_azimuth*(AZIMUTH_SMOOTHING_FACTOR/100));
}
if (raw_azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = raw_azimuth - (360 * HEADING_MULTIPLIER);
if (azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = azimuth - (360 * HEADING_MULTIPLIER);
}
} else {
if (raw_azimuth < 0) {
azimuth = raw_azimuth + (360 * HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
}
remote_unit_command_results_available = 0;
} else {
// is it time to request the azimuth?
if ((millis() - last_remote_unit_az_query_time) > AZ_REMOTE_UNIT_QUERY_TIME_MS){
if (submit_remote_command(REMOTE_UNIT_AZ_COMMAND)) {
last_remote_unit_az_query_time = millis();
}
}
}
#endif //FEATURE_AZ_POSITION_GET_FROM_REMOTE_UNIT
#ifdef FEATURE_AZ_POSITION_ROTARY_ENCODER
static byte az_position_encoder_state = 0;
az_position_encoder_state = ttable[az_position_encoder_state & 0xf][((digitalRead(az_rotary_position_pin2) << 1) | digitalRead(az_rotary_position_pin1))];
byte az_position_encoder_result = az_position_encoder_state & 0x30;
if (az_position_encoder_result) {
if (az_position_encoder_result == DIR_CW) {
configuration.last_azimuth = configuration.last_azimuth + AZ_POSITION_ROTARY_ENCODER_DEG_PER_PULSE;
#ifdef DEBUG_POSITION_ROTARY_ENCODER
if (debug_mode){Serial.println(F("read_azimuth: AZ_POSITION_ROTARY_ENCODER: CW"));}
#endif //DEBUG_POSITION_ROTARY_ENCODER
}
if (az_position_encoder_result == DIR_CCW) {
configuration.last_azimuth = configuration.last_azimuth - AZ_POSITION_ROTARY_ENCODER_DEG_PER_PULSE;
#ifdef DEBUG_POSITION_ROTARY_ENCODER
if (debug_mode){Serial.println(F("read_azimuth: AZ_POSITION_ROTARY_ENCODER: CCW"));}
#endif //DEBUG_POSITION_ROTARY_ENCODER
}
#ifdef OPTION_AZ_POSITION_ROTARY_ENCODER_HARD_LIMIT
if (configuration.last_azimuth < configuration.azimuth_starting_point){
configuration.last_azimuth = configuration.azimuth_starting_point;
}
if (configuration.last_azimuth > (configuration.azimuth_starting_point + configuration.azimuth_rotation_capability)){
configuration.last_azimuth = (configuration.azimuth_starting_point + configuration.azimuth_rotation_capability);
}
#else
if (configuration.last_azimuth < 0){
configuration.last_azimuth += 360;
}
if (configuration.last_azimuth >= 360){
configuration.last_azimuth -= 360;
}
#endif //OPTION_AZ_POSITION_ROTARY_ENCODER_HARD_LIMIT
raw_azimuth = int(configuration.last_azimuth * HEADING_MULTIPLIER);
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
if (raw_azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = raw_azimuth - (360 * HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
configuration_dirty = 1;
}
#endif //FEATURE_AZ_POSITION_ROTARY_ENCODER
#ifdef FEATURE_AZ_POSITION_HMC5883L
MagnetometerScaled scaled = compass.ReadScaledAxis(); //scaled values from compass.
float heading = atan2(scaled.YAxis, scaled.XAxis);
// heading += declinationAngle;
// Correct for when signs are reversed.
if(heading < 0) heading += 2*PI;
if(heading > 2*PI) heading -= 2*PI;
raw_azimuth = (heading * RAD_TO_DEG) * HEADING_MULTIPLIER; //radians to degree
if (AZIMUTH_SMOOTHING_FACTOR > 0) {
raw_azimuth = (raw_azimuth*(1-(AZIMUTH_SMOOTHING_FACTOR/100))) + (previous_raw_azimuth*(AZIMUTH_SMOOTHING_FACTOR/100));
}
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
azimuth = raw_azimuth;
#endif // FEATURE_AZ_POSITION_HMC5883L
#ifdef FEATURE_AZ_POSITION_LSM303
lsm.read();
float heading = atan2(lsm.magData.y,lsm.magData.x);
// heading += declinationAngle;
// Correct for when signs are reversed.
if(heading < 0) heading += 2*PI;
if(heading > 2*PI) heading -= 2*PI;
raw_azimuth = (heading * RAD_TO_DEG) * HEADING_MULTIPLIER; //radians to degree
if (AZIMUTH_SMOOTHING_FACTOR > 0) {
raw_azimuth = (raw_azimuth*(1-(AZIMUTH_SMOOTHING_FACTOR/100))) + (previous_raw_azimuth*(AZIMUTH_SMOOTHING_FACTOR/100));
}
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
azimuth = raw_azimuth;
#endif // FEATURE_AZ_POSITION_LSM303
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
#ifdef DEBUG_POSITION_PULSE_INPUT
// if (az_position_pule_interrupt_handler_flag) {
// Serial.print(F("read_azimuth: az_position_pusle_interrupt_handler_flag: "));
// Serial.println(az_position_pule_interrupt_handler_flag);
// az_position_pule_interrupt_handler_flag = 0;
// }
#endif //DEBUG_POSITION_PULSE_INPUT
//dddd
static float last_az_position_pulse_input_azimuth = az_position_pulse_input_azimuth;
if (az_position_pulse_input_azimuth != last_az_position_pulse_input_azimuth){
#ifdef DEBUG_POSITION_PULSE_INPUT
// if (debug_mode){
// Serial.print(F("read_azimuth: last_az_position_pulse_input_azimuth:"));
// Serial.print(last_az_position_pulse_input_azimuth);
// Serial.print(F(" az_position_pulse_input_azimuth:"));
// Serial.print(az_position_pulse_input_azimuth);
// Serial.print(F(" az_pulse_counter:"));
// Serial.println(az_pulse_counter);
// }
#endif //DEBUG_POSITION_PULSE_INPUT
configuration.last_azimuth = az_position_pulse_input_azimuth;
configuration_dirty = 1;
last_az_position_pulse_input_azimuth = az_position_pulse_input_azimuth;
raw_azimuth = int(configuration.last_azimuth * HEADING_MULTIPLIER);
#ifdef FEATURE_AZIMUTH_CORRECTION
raw_azimuth = (correct_azimuth(raw_azimuth/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_AZIMUTH_CORRECTION
if (raw_azimuth >= (360 * HEADING_MULTIPLIER)) {
azimuth = raw_azimuth - (360 * HEADING_MULTIPLIER);
} else {
azimuth = raw_azimuth;
}
}
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
last_measurement_time = millis();
}
}
//--------------------------------------------------------------
void output_debug()
{
if (((millis() - last_debug_output_time) >= 3000) && (debug_mode)) {
Serial.flush();
Serial.print("debug: \t");
Serial.print(CODE_VERSION);
Serial.print("\t\t");
Serial.print(millis()/1000);
Serial.print("\t\t");
#ifdef DEBUG_MEMORY
void* HP = malloc(4);
if (HP) {
free (HP);
}
unsigned long free = (unsigned long)SP - (unsigned long)HP;
// if (free > 2048) {
// free = 0;
// }
Serial.print((unsigned long)free,DEC);
Serial.print(F("b free"));
#endif
#ifdef FEATURE_YAESU_EMULATION
Serial.print(F("\t\tGS-232"));
#ifdef OPTION_GS_232B_EMULATION
Serial.print(F("B"));
#endif
#ifndef OPTION_GS_232B_EMULATION
Serial.print(F("A"));
#endif
#endif //FEATURE_YAESU_EMULATIO
Serial.println();
Serial.print(F("\tAZ: "));
switch (az_state) {
case IDLE: Serial.print(F("IDLE")); break;
case SLOW_START_CW: Serial.print(F("SLOW_START_CW")); break;
case SLOW_START_CCW: Serial.print(F("SLOW_START_CCW")); break;
case NORMAL_CW: Serial.print(F("NORMAL_CW")); break;
case NORMAL_CCW: Serial.print(F("NORMAL_CCW")); break;
case SLOW_DOWN_CW: Serial.print(F("SLOW_DOWN_CW")); break;
case SLOW_DOWN_CCW: Serial.print(F("SLOW_DOWN_CCW")); break;
case INITIALIZE_SLOW_START_CW: Serial.print(F("INITIALIZE_SLOW_START_CW")); break;
case INITIALIZE_SLOW_START_CCW: Serial.print(F("INITIALIZE_SLOW_START_CCW")); break;
case INITIALIZE_TIMED_SLOW_DOWN_CW: Serial.print(F("INITIALIZE_TIMED_SLOW_DOWN_CW")); break;
case INITIALIZE_TIMED_SLOW_DOWN_CCW: Serial.print(F("INITIALIZE_TIMED_SLOW_DOWN_CCW")); break;
case TIMED_SLOW_DOWN_CW: Serial.print(F("TIMED_SLOW_DOWN_CW")); break;
case TIMED_SLOW_DOWN_CCW: Serial.print(F("TIMED_SLOW_DOWN_CCW")); break;
}
Serial.print(F("\tQ: "));
switch(az_request_queue_state){
case NONE: Serial.print(F("-")); break;
case IN_QUEUE: Serial.print(F("IN_QUEUE")); break;
case IN_PROGRESS_TIMED: Serial.print(F("IN_PROGRESS_TIMED")); break;
case IN_PROGRESS_TO_TARGET: Serial.print(F("IN_PROGRESS_TO_TARGET")); break;
}
Serial.print(F("\tAZ: "));
Serial.print(azimuth/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
Serial.print(F(" (raw: "));
Serial.print(raw_azimuth/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
Serial.print(")");
Serial.print(F("\tTarget: "));
Serial.print(target_azimuth/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
Serial.print(F(" (raw: "));
Serial.print(target_raw_azimuth/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
Serial.print(")");
#ifdef FEATURE_AZ_POSITION_POTENTIOMETER
Serial.print(F("\tAnalog: "));
Serial.println(analog_az);
#endif //FEATURE_AZ_POSITION_POTENTIOMETER
//if (azimuth_speed_voltage) {
Serial.print(F("\tAZ Speed Norm: "));
Serial.print(normal_az_speed_voltage, DEC);
//}
Serial.print(F(" Current: "));
Serial.print(current_az_speed_voltage,DEC);
if (az_speed_pot) {
Serial.print(F("\tAZ Speed Pot: "));
Serial.print(analogRead(az_speed_pot));
}
if (az_preset_pot) {
Serial.print(F("\tAZ Preset Pot Analog: "));
Serial.print(analogRead(az_preset_pot));
Serial.print(F("\tAZ Preset Pot Setting: "));
Serial.print(map(analogRead(az_preset_pot), AZ_PRESET_POT_FULL_CW, AZ_PRESET_POT_FULL_CCW, AZ_PRESET_POT_FULL_CW_MAP, AZ_PRESET_POT_FULL_CCW_MAP));
}
Serial.println();
#ifdef FEATURE_ELEVATION_CONTROL
Serial.print(F("\tEL: "));
switch (el_state) {
case IDLE: Serial.print(F("IDLE")); break;
case SLOW_START_UP: Serial.print(F("SLOW_START_UP")); break;
case SLOW_START_DOWN: Serial.print(F("SLOW_START_DOWN")); break;
case NORMAL_UP: Serial.print(F("NORMAL_UP")); break;
case NORMAL_DOWN: Serial.print(F("NORMAL_DOWN")); break;
case SLOW_DOWN_DOWN: Serial.print(F("SLOW_DOWN_DOWN")); break;
case SLOW_DOWN_UP: Serial.print(F("SLOW_DOWN_UP")); break;
case TIMED_SLOW_DOWN_UP: Serial.print(F("TIMED_SLOW_DOWN_UP")); break;
case TIMED_SLOW_DOWN_DOWN: Serial.print(F("TIMED_SLOW_DOWN_DOWN")); break;
}
Serial.print(F("\tQ: "));
switch (el_request_queue_state) {
case NONE: Serial.print(F("-")); break;
case IN_QUEUE: Serial.print(F("IN_QUEUE")); break;
case IN_PROGRESS_TIMED: Serial.print(F("IN_PROGRESS_TIMED")); break;
case IN_PROGRESS_TO_TARGET: Serial.print(F("IN_PROGRESS_TO_TARGET")); break;
}
#ifdef FEATURE_EL_POSITION_POTENTIOMETER
Serial.print(F("\tEL Analog: "));
Serial.print(analog_el);
#endif //FEATURE_EL_POSITION_POTENTIOMETER
Serial.print(F("\tEL: "));
Serial.print(elevation/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
Serial.print(F("\tTarget: "));
Serial.println(target_elevation/LCD_HEADING_MULTIPLIER,LCD_DECIMAL_PLACES);
#endif //FEATURE_EL_POSITION_POTENTIOMETER
#ifdef FEATURE_TIMED_BUFFER
if (timed_buffer_status != EMPTY) {
Serial.print(F("\tTimed interval buff: "));
switch (timed_buffer_status) {
//case EMPTY: Serial.print(F("EMPTY")); break;
case LOADED_AZIMUTHS: Serial.print(F("LOADED_AZIMUTHS")); break;
case RUNNING_AZIMUTHS: Serial.print(F("RUNNING_AZIMUTHS")); break;
#ifdef FEATURE_ELEVATION_CONTROL
case LOADED_AZIMUTHS_ELEVATIONS: Serial.print(F("LOADED_AZIMUTHS_ELEVATIONS")); break;
case RUNNING_AZIMUTHS_ELEVATIONS: Serial.print(F("RUNNING_AZIMUTHS_ELEVATIONS")); break;
#endif
}
Serial.print(F("\tInterval (secs): "));
Serial.print(timed_buffer_interval_value_seconds,DEC);
Serial.print(F("\tEntries: "));
Serial.print(timed_buffer_number_entries_loaded,DEC);
Serial.print(F("\tEntry ptr: "));
Serial.print(timed_buffer_entry_pointer,DEC);
Serial.print(F("\tSecs since last action: "));
Serial.println((millis()-last_timed_buffer_action_time)/1000);
if (timed_buffer_number_entries_loaded > 0) {
for (int x = 0;x < timed_buffer_number_entries_loaded; x++) {
Serial.print(x+1);
Serial.print(F("\t:"));
Serial.print(timed_buffer_azimuths[x]/HEADING_MULTIPLIER);
#ifdef FEATURE_ELEVATION_CONTROL
Serial.print(F("\t- "));
Serial.print(timed_buffer_elevations[x]/HEADING_MULTIPLIER);
#endif
Serial.println();
}
}
} //if (timed_buffer_status != EMPTY)
#endif //FEATURE_TIMED_BUFFER
Serial.print(F("\tAZ: "));
Serial.print(configuration.azimuth_starting_point);
Serial.print(F("+"));
Serial.print(configuration.azimuth_rotation_capability);
Serial.print(F("\tAZ ana: "));
Serial.print(configuration.analog_az_full_ccw);
Serial.print(F("-"));
Serial.print(configuration.analog_az_full_cw);
#ifdef FEATURE_ELEVATION_CONTROL
Serial.print(F("\tEL ana: "));
Serial.print(configuration.analog_el_0_degrees);
Serial.print(F("-"));
Serial.print(configuration.analog_el_max_elevation);
#endif
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
Serial.print(F("\n\tRemote: Command: "));
Serial.print(remote_unit_command_submitted);
Serial.print(F(" Good: "));
Serial.print(remote_unit_good_results);
Serial.print(F(" Bad: "));
Serial.print(remote_unit_bad_results);
Serial.print(F(" Index: "));
Serial.print(serial1_buffer_index);
Serial.print(F(" CmdTouts: "));
Serial.print(remote_unit_command_timeouts);
Serial.print(F(" BuffTouts: "));
Serial.print(remote_unit_incoming_buffer_timeouts);
Serial.print(F(" Result: "));
Serial.println(remote_unit_command_result_float);
#endif //#FEATURE_HOST_REMOTE_PROTOCOL
#ifdef DEBUG_POSITION_PULSE_INPUT
static unsigned long last_pulse_count_time = 0;
static unsigned long last_az_pulse_counter = 0;
static unsigned long last_el_pulse_counter = 0;
Serial.print(F("\n\tPulse counters: AZ: "));
Serial.print(az_pulse_counter);
Serial.print(F(" AZ Ambiguous: "));
Serial.print(az_pulse_counter_ambiguous);
Serial.print(" EL: ");
Serial.print(el_pulse_counter);
Serial.print(F(" EL Ambiguous: "));
Serial.print(el_pulse_counter_ambiguous);
Serial.print(F(" Rate per sec: AZ: "));
Serial.print((az_pulse_counter-last_az_pulse_counter)/((millis()-last_pulse_count_time)/1000.0));
Serial.print(F(" EL: "));
Serial.println((el_pulse_counter-last_el_pulse_counter)/((millis()-last_pulse_count_time)/1000.0));
last_az_pulse_counter = az_pulse_counter;
last_el_pulse_counter = el_pulse_counter;
last_pulse_count_time = millis();
#endif //DEBUG_POSITION_PULSE_INPUT
Serial.println(F("\n\n\n\n"));
last_debug_output_time = millis();
}
}
//--------------------------------------------------------------
void report_current_azimuth() {
#ifdef FEATURE_YAESU_EMULATION
// The C command that reports azimuth
String azimuth_string;
#ifndef OPTION_GS_232B_EMULATION
Serial.print(F("+0"));
#endif
#ifdef OPTION_GS_232B_EMULATION
Serial.print(F("AZ="));
#endif
//Serial.write("report_current_azimith: azimuth=");
//Serial.println(azimuth);
azimuth_string = String(int(azimuth/HEADING_MULTIPLIER), DEC);
if (azimuth_string.length() == 1) {
Serial.print(F("00"));
} else {
if (azimuth_string.length() == 2) {
Serial.print(F("0"));
}
}
Serial.print(azimuth_string);
#ifdef FEATURE_ELEVATION_CONTROL
#ifndef OPTION_C_COMMAND_SENDS_AZ_AND_EL
if ((serial0_buffer[1] == '2') && (serial0_buffer_index > 1)) { // did we get the C2 command?
#endif
report_current_elevation();
#ifndef OPTION_C_COMMAND_SENDS_AZ_AND_EL
} else {
Serial.println();
}
#endif //OPTION_C_COMMAND_SENDS_AZ_AND_EL
#endif //FEATURE_ELEVATION_CONTROL
#ifndef FEATURE_ELEVATION_CONTROL
if ((serial0_buffer[1] == '2') && (serial0_buffer_index > 1)) { // did we get the C2 command?
#ifndef OPTION_GS_232B_EMULATION
Serial.println(F("+0000")); // return a dummy elevation since we don't have the elevation feature turned on
#else
Serial.println(F("EL=000"));
#endif
} else {
Serial.println();
}
#endif //FEATURE_ELEVATION_CONTROL
#endif //FEATURE_YAESU_EMULATION
}
//--------------------------------------------------------------
void print_help(){
// The H command
#ifdef OPTION_SERIAL_HELP_TEXT
#ifdef FEATURE_YAESU_EMULATION
Serial.println(F("R Rotate Azimuth Clockwise"));
Serial.println(F("L Rotate Azimuth Counter Clockwise"));
Serial.println(F("A Stop"));
Serial.println(F("C Report Azimuth in Degrees"));
Serial.println(F("M### Rotate to ### degrees"));
Serial.println(F("MTTT XXX XXX XXX ... Timed Interval Direction Setting (TTT = Step value in seconds, XXX = Azimuth in degrees)"));
Serial.println(F("T Start Timed Interval Tracking"));
Serial.println(F("N Report Total Number of M Timed Interval Azimuths"));
Serial.println(F("X1 Horizontal Rotation Low Speed"));
Serial.println(F("X2 Horizontal Rotation Middle 1 Speed"));
Serial.println(F("X3 Horizontal Rotation Middle 2 Speed"));
Serial.println(F("X4 Horizontal Rotation High Speed"));
Serial.println(F("S Stop"));
Serial.println(F("O Offset Calibration"));
Serial.println(F("F Full Scale Calibration"));
#ifdef FEATURE_ELEVATION_CONTROL
Serial.println(F("U Rotate Elevation Up"));
Serial.println(F("D Rotate Elevation Down"));
Serial.println(F("E Stop Elevation Rotation"));
Serial.println(F("B Report Elevation in Degrees"));
Serial.println(F("Wxxx yyy Rotate Azimuth to xxx Degrees and Elevation to yyy Degrees\r\r"));
Serial.println(F("O2 Elevation Offset Calibration (0 degrees)"));
Serial.println(F("F2 Elevation Full Scale Calibration (180 degrees (or maximum))"));
#endif //FEATURE_ELEVATION_CONTROL
#endif //FEATURE_YAESU_EMULATION
#endif //OPTION_SERIAL_HELP_TEXT
}
//--------------- Elevation -----------------------
#ifdef FEATURE_ELEVATION_CONTROL
void el_check_operation_timeout()
{
// check if the last executed rotation operation has been going on too long
if (((millis() - el_last_rotate_initiation) > OPERATION_TIMEOUT) && (el_state != IDLE)) {
submit_request(EL,REQUEST_KILL,0);
#ifdef DEBUG_EL_CHECK_OPERATION_TIMEOUT
if (debug_mode) {
Serial.println(F("el_check_operation_timeout: timeout reached, aborting rotation"));
}
#endif //DEBUG_EL_CHECK_OPERATION_TIMEOUT
}
}
#endif
//--------------------------------------------------------------
//#ifdef FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_YAESU_EMULATION
void yaesu_w_command ()
{
// parse out W command
// Short Format: WXXX YYY = azimuth YYY = elevation
// Long Format : WSSS XXX YYY SSS = timed interval XXX = azimuth YYY = elevation
int parsed_elevation = 0;
int parsed_azimuth = 0;
//int parsed_value1 = 0;
//int parsed_value2 = 0;
if (serial0_buffer_index > 8) { // if there are more than 4 characters in the command buffer, we got a timed interval command
#ifdef FEATURE_TIMED_BUFFER
parsed_value1 = ((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48);
if ((parsed_value1 > 0) && (parsed_value1 < 1000)) {
timed_buffer_interval_value_seconds = parsed_value1;
for (int x = 5; x < serial0_buffer_index; x = x + 8) {
parsed_value1 = ((int(serial0_buffer[x])-48)*100) + ((int(serial0_buffer[x+1])-48)*10) + (int(serial0_buffer[x+2])-48);
parsed_value2 = ((int(serial0_buffer[x+4])-48)*100) + ((int(serial0_buffer[x+5])-48)*10) + (int(serial0_buffer[x+6])-48);
if ((parsed_value1 > -1) && (parsed_value1 < 361) && (parsed_value2 > -1) && (parsed_value2 < 181)) { // is it a valid azimuth?
timed_buffer_azimuths[timed_buffer_number_entries_loaded] = (parsed_value1 * HEADING_MULTIPLIER);
timed_buffer_elevations[timed_buffer_number_entries_loaded] = (parsed_value2 * HEADING_MULTIPLIER);
timed_buffer_number_entries_loaded++;
timed_buffer_status = LOADED_AZIMUTHS_ELEVATIONS;
if (timed_buffer_number_entries_loaded > TIMED_INTERVAL_ARRAY_SIZE) { // is the array full?
x = serial0_buffer_index; // array is full, go to the first azimuth and elevation
}
} else { // we hit an invalid bearing
timed_buffer_status = EMPTY;
timed_buffer_number_entries_loaded = 0;
Serial.println(F("?>")); // error
return;
}
}
}
timed_buffer_entry_pointer = 1; // go to the first bearings
parsed_azimuth = timed_buffer_azimuths[0];
parsed_elevation = timed_buffer_elevations[0];
#else
Serial.println(F("Feature not activated ?>"));
#endif //FEATURE_TIMED_BUFFER
} else {
// this is a short form W command, just parse the azimuth and elevation and initiate rotation
parsed_azimuth = (((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48)) * HEADING_MULTIPLIER;
parsed_elevation = (((int(serial0_buffer[5])-48)*100) + ((int(serial0_buffer[6])-48)*10) + (int(serial0_buffer[7])-48)) * HEADING_MULTIPLIER;
}
if ((parsed_azimuth >= 0) && (parsed_azimuth <= (360*HEADING_MULTIPLIER))) {
submit_request(AZ,REQUEST_AZIMUTH,parsed_azimuth);
} else {
#ifdef DEBUG_YAESU
if (debug_mode) {Serial.println(F("yaesu_w_command: W command elevation error"));}
#endif //DEBUG_YAESU
Serial.println(F("?>")); // bogus elevation - return and error and don't do anything
return;
}
#ifdef FEATURE_ELEVATION_CONTROL
if ((parsed_elevation >= 0) && (parsed_elevation <= (180 * HEADING_MULTIPLIER))) {
submit_request(EL,REQUEST_ELEVATION,parsed_elevation);
} else {
#ifdef DEBUG_YAESU
if (debug_mode) {Serial.println(F("yaesu_w_command: W command elevation error"));}
#endif //DEBUG_YAESU
Serial.println(F("?>")); // bogus elevation - return and error and don't do anything
return;
}
#endif //FEATURE_ELEVATION_CONTROL
Serial.println();
}
#endif //FEATURE_YAESU_EMULATION
//#endif //FEATURE_ELEVATION_CONTROL
//--------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
void read_elevation()
{
// read analog input and convert it to degrees
unsigned int previous_elevation = elevation;
static unsigned long last_measurement_time = 0;
#ifdef DEBUG_HEADING_READING_TIME
static unsigned long last_time = 0;
static unsigned long last_print_time = 0;
static float average_read_time = 0;
#endif //DEBUG_HEADING_READING_TIME
#ifndef FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
if ((millis() - last_measurement_time) > ELEVATION_MEASUREMENT_FREQUENCY_MS){
#else
if (1){
#endif
#ifdef FEATURE_EL_POSITION_POTENTIOMETER
analog_el = analogRead(rotator_analog_el);
elevation = (map(analog_el, configuration.analog_el_0_degrees, configuration.analog_el_max_elevation, 0, (ELEVATION_MAXIMUM_DEGREES* HEADING_MULTIPLIER))) ;
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
if (ELEVATION_SMOOTHING_FACTOR > 0) {
elevation = (elevation*(1-(ELEVATION_SMOOTHING_FACTOR/100))) + (previous_elevation*(ELEVATION_SMOOTHING_FACTOR/100));
}
if (elevation < 0) {
elevation = 0;
}
#endif //FEATURE_EL_POSITION_POTENTIOMETER
#ifdef FEATURE_EL_POSITION_ROTARY_ENCODER
static byte el_position_encoder_state = 0;
el_position_encoder_state = ttable[el_position_encoder_state & 0xf][((digitalRead(el_rotary_position_pin2) << 1) | digitalRead(el_rotary_position_pin1))];
byte el_position_encoder_result = el_position_encoder_state & 0x30;
if (el_position_encoder_result) {
if (el_position_encoder_result == DIR_CW) {
configuration.last_elevation = configuration.last_elevation + EL_POSITION_ROTARY_ENCODER_DEG_PER_PULSE;
#ifdef DEBUG_POSITION_ROTARY_ENCODER
if (debug_mode){Serial.println(F("read_elevation: EL_POSITION_ROTARY_ENCODER: CW/UP"));}
#endif //DEBUG_POSITION_ROTARY_ENCODER
}
if (el_position_encoder_result == DIR_CCW) {
configuration.last_elevation = configuration.last_elevation - EL_POSITION_ROTARY_ENCODER_DEG_PER_PULSE;
#ifdef DEBUG_POSITION_ROTARY_ENCODER
if (debug_mode){Serial.println(F("read_elevation: EL_POSITION_ROTARY_ENCODER: CCW/DWN"));}
#endif //DEBUG_POSITION_ROTARY_ENCODER
}
#ifdef OPTION_EL_POSITION_ROTARY_ENCODER_HARD_LIMIT
if (configuration.last_elevation < 0){
configuration.last_elevation = 0;
}
if (configuration.last_elevation > ELEVATION_MAXIMUM_DEGREES){
configuration.last_elevation = ELEVATION_MAXIMUM_DEGREES ;
}
#endif
elevation = int(configuration.last_elevation * HEADING_MULTIPLIER);
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
configuration_dirty = 1;
}
#endif //FEATURE_EL_POSITION_ROTARY_ENCODER
#ifdef FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB
AccelerometerRaw raw = accel.ReadRawAxis();
AccelerometerScaled scaled = accel.ReadScaledAxis();
#ifdef DEBUG_ACCEL
if (debug_mode) {
Serial.print(F("read_elevation: raw.ZAxis: "));
Serial.println(raw.ZAxis);
}
#endif //DEBUG_ACCEL
elevation = (atan2(scaled.YAxis,scaled.ZAxis)* 180 * HEADING_MULTIPLIER)/M_PI;
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
if (ELEVATION_SMOOTHING_FACTOR > 0) {
elevation = (elevation*(1-(ELEVATION_SMOOTHING_FACTOR/100))) + (previous_elevation*(ELEVATION_SMOOTHING_FACTOR/100));
}
#endif //FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB
#ifdef FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB
sensors_event_t event;
accel.getEvent(&event);
#ifdef DEBUG_ACCEL
if (debug_mode) {
Serial.print(F("read_elevation: event.acceleration.z: "));
Serial.println(event.acceleration.z);
}
#endif //DEBUG_ACCEL
elevation = (atan2(event.acceleration.y,event.acceleration.z)* 180 * HEADING_MULTIPLIER)/M_PI;
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
#endif //FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB
#ifdef FEATURE_EL_POSITION_LSM303
lsm.read();
#ifdef DEBUG_ACCEL
if (debug_mode) {
Serial.print(F("read_elevation: lsm.accelData.y: "));
Serial.print(lsm.accelData.y);
Serial.print(F(" lsm.accelData.z: "));
Serial.println(lsm.accelData.z);
}
#endif //DEBUG_ACCEL
elevation = (atan2(lsm.accelData.y,lsm.accelData.z)* 180 * HEADING_MULTIPLIER)/M_PI;
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
#endif //FEATURE_EL_POSITION_LSM303
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
#ifdef DEBUG_POSITION_PULSE_INPUT
// if (el_position_pule_interrupt_handler_flag) {
// Serial.print(F("read_elevation: el_position_pule_interrupt_handler_flag: "));
// Serial.println(el_position_pule_interrupt_handler_flag);
// el_position_pule_interrupt_handler_flag = 0;
// }
#endif //DEBUG_POSITION_PULSE_INPUT
static float last_el_position_pulse_input_elevation = el_position_pulse_input_elevation;
if (el_position_pulse_input_elevation != last_el_position_pulse_input_elevation){
#ifdef DEBUG_POSITION_PULSE_INPUT
// if (debug_mode){
// Serial.print(F("read_elevation: el_position_pulse_input_elevation:"));
// Serial.println(el_position_pulse_input_elevation);
// }
#endif //DEBUG_POSITION_PULSE_INPUT
configuration.last_elevation = el_position_pulse_input_elevation;
configuration_dirty = 1;
last_el_position_pulse_input_elevation = el_position_pulse_input_elevation;
elevation = int(configuration.last_elevation * HEADING_MULTIPLIER);
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif FEATURE_ELEVATION_CORRECTION
}
#endif //FEATURE_EL_POSITION_PULSE_INPUT
#ifdef FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
static unsigned long last_remote_unit_el_query_time = 0;
// do we have a command result waiting for us?
if (remote_unit_command_results_available == REMOTE_UNIT_EL_COMMAND) {
#ifdef DEBUG_HEADING_READING_TIME
average_read_time = (average_read_time + (millis()-last_time))/2.0;
last_time = millis();
if (debug_mode){
if ((millis()-last_print_time) > 1000){
Serial.print(F("read_elevation: avg read frequency: "));
Serial.println(average_read_time,2);
last_print_time = millis();
}
}
#endif //DEBUG_HEADING_READING_TIME
elevation = remote_unit_command_result_float * HEADING_MULTIPLIER;
#ifdef FEATURE_ELEVATION_CORRECTION
elevation = (correct_elevation(elevation/HEADING_MULTIPLIER)*HEADING_MULTIPLIER);
#endif //FEATURE_ELEVATION_CORRECTION
if (ELEVATION_SMOOTHING_FACTOR > 0) {
elevation = (elevation*(1-(ELEVATION_SMOOTHING_FACTOR/100))) + (previous_elevation*(ELEVATION_SMOOTHING_FACTOR/100));
}
remote_unit_command_results_available = 0;
} else {
// is it time to request the elevation?
if ((millis() - last_remote_unit_el_query_time) > EL_REMOTE_UNIT_QUERY_TIME_MS){
if (submit_remote_command(REMOTE_UNIT_EL_COMMAND)){
last_remote_unit_el_query_time = millis();
}
}
}
#endif //FEATURE_EL_POSITION_GET_FROM_REMOTE_UNIT
last_measurement_time = millis();
}
}
#endif
//--------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
void report_current_elevation() {
#ifdef FEATURE_YAESU_EMULATION
// The C2 command that reports elevation in +0nnn format
String elevation_string;
#ifndef OPTION_GS_232B_EMULATION
if (elevation < 0){
Serial.print(F("-0"));
} else {
Serial.print(F("+0"));
}
#endif
#ifdef OPTION_GS_232B_EMULATION
Serial.print(F("EL="));
#endif
elevation_string = String(abs(int(elevation/HEADING_MULTIPLIER)), DEC);
if (elevation_string.length() == 1) {
Serial.print(F("00"));
} else {
if (elevation_string.length() == 2) {
Serial.print(F("0"));
}
}
Serial.println(elevation_string);
#endif //FEATURE_YAESU_EMULATION
}
#endif
//--------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
void update_el_variable_outputs(byte speed_voltage){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {
Serial.print(F("update_el_variable_outputs: speed_voltage: "));
Serial.print(speed_voltage);
}
#endif //DEBUG_VARIABLE_OUTPUTS
if (((el_state == SLOW_START_UP) || (el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (rotate_up_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_up_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_up_pwm,speed_voltage);
}
if (((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) && (rotate_down_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_down_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_down_pwm,speed_voltage);
}
if (((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN) ||
(el_state == SLOW_START_UP) || (el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (rotate_up_down_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_up_down_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_up_down_pwm,speed_voltage);
}
if (((el_state == SLOW_START_UP) || (el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (rotate_up_freq)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_up_freq"));}
#endif //DEBUG_VARIABLE_OUTPUTS
tone(rotate_up_freq,map(speed_voltage,0,255,EL_VARIABLE_FREQ_OUTPUT_LOW,EL_VARIABLE_FREQ_OUTPUT_HIGH));
}
if (((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) && (rotate_down_freq)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_down_freq"));}
#endif //DEBUG_VARIABLE_OUTPUTS
tone(rotate_down_freq,map(speed_voltage,0,255,EL_VARIABLE_FREQ_OUTPUT_LOW,EL_VARIABLE_FREQ_OUTPUT_HIGH));
}
if (elevation_speed_voltage){
analogWrite(elevation_speed_voltage,speed_voltage);
}
if (debug_mode) {Serial.println();}
current_el_speed_voltage = speed_voltage;
}
#endif //FEATURE_ELEVATION_CONTROL
//--------------------------------------------------------------
void update_az_variable_outputs(byte speed_voltage){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {
Serial.print(F("update_az_variable_outputs: speed_voltage: "));
Serial.print(speed_voltage);
}
#endif //DEBUG_VARIABLE_OUTPUTS
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) && (rotate_cw_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_cw_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_cw_pwm,speed_voltage);
}
if (((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (rotate_ccw_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_ccw_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_ccw_pwm,speed_voltage);
}
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW) || (az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (rotate_cw_ccw_pwm)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_cw_ccw_pwm"));}
#endif //DEBUG_VARIABLE_OUTPUTS
analogWrite(rotate_cw_ccw_pwm,speed_voltage);
}
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) && (rotate_cw_freq)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_cw_freq"));}
#endif //DEBUG_VARIABLE_OUTPUTS
tone(rotate_cw_freq,map(speed_voltage,0,255,AZ_VARIABLE_FREQ_OUTPUT_LOW,AZ_VARIABLE_FREQ_OUTPUT_HIGH));
}
if (((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (rotate_ccw_freq)){
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.print(F("\trotate_ccw_freq"));}
#endif //DEBUG_VARIABLE_OUTPUTS
tone(rotate_ccw_freq,map(speed_voltage,0,255,AZ_VARIABLE_FREQ_OUTPUT_LOW,AZ_VARIABLE_FREQ_OUTPUT_HIGH));
}
if (azimuth_speed_voltage) {
analogWrite(azimuth_speed_voltage,speed_voltage);
}
#ifdef DEBUG_VARIABLE_OUTPUTS
if (debug_mode) {Serial.println();}
#endif //DEBUG_VARIABLE_OUTPUTS
current_az_speed_voltage = speed_voltage;
}
//--------------------------------------------------------------
void rotator(byte rotation_action, byte rotation_type) {
#ifdef DEBUG_ROTATOR
if (debug_mode) {
Serial.flush();
Serial.print(F("rotator: rotation_action:"));
Serial.print(rotation_action);
Serial.print(F(" rotation_type:"));
Serial.flush();
Serial.print(rotation_type);
Serial.print(F("->"));
Serial.flush();
//delay(1000);
}
#endif //DEBUG_ROTATOR
switch(rotation_type) {
case CW:
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.print(F("CW ")); Serial.flush();}
#endif //DEBUG_ROTATOR
if (rotation_action == ACTIVATE) {
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.println(F("ACTIVATE")); Serial.flush();}
#endif //DEBUG_ROTATOR
brake_release(AZ, BRAKE_RELEASE_ON);
if (az_slowstart_active) {
if (rotate_cw_pwm) {analogWrite(rotate_cw_pwm,0);}
if (rotate_ccw_pwm) {analogWrite(rotate_ccw_pwm,0);digitalWrite(rotate_ccw_pwm,LOW);}
if (rotate_cw_ccw_pwm) {analogWrite(rotate_cw_ccw_pwm,0);}
if (rotate_cw_freq) {noTone(rotate_cw_freq);}
if (rotate_ccw_freq) {noTone(rotate_ccw_freq);}
} else {
if (rotate_cw_pwm) {analogWrite(rotate_cw_pwm,normal_az_speed_voltage);}
if (rotate_ccw_pwm) {analogWrite(rotate_ccw_pwm,0);digitalWrite(rotate_ccw_pwm,LOW);}
if (rotate_cw_ccw_pwm) {analogWrite(rotate_cw_ccw_pwm,normal_az_speed_voltage);}
if (rotate_cw_freq) {tone(rotate_cw_freq,map(normal_az_speed_voltage,0,255,AZ_VARIABLE_FREQ_OUTPUT_LOW,AZ_VARIABLE_FREQ_OUTPUT_HIGH));}
if (rotate_ccw_freq) {noTone(rotate_ccw_freq);}
}
if (rotate_cw) {digitalWrite(rotate_cw,ROTATE_PIN_ACTIVE_VALUE);}
if (rotate_ccw) {digitalWrite(rotate_ccw,ROTATE_PIN_INACTIVE_VALUE);}
#ifdef DEBUG_ROTATOR
if (debug_mode) {
Serial.print(F("rotator: normal_az_speed_voltage:"));
Serial.println(normal_az_speed_voltage);
Serial.flush();
}
#endif //DEBUG_ROTATOR
} else {
#ifdef DEBUG_ROTATOR
if (debug_mode) {Serial.println(F("DEACTIVATE"));Serial.flush();}
#endif //DEBUG_ROTATOR
if (rotate_cw_pwm) {analogWrite(rotate_cw_pwm,0);digitalWrite(rotate_cw_pwm,LOW);}
if (rotate_cw_ccw_pwm) {analogWrite(rotate_cw_ccw_pwm,0);}
if (rotate_cw) {digitalWrite(rotate_cw,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_cw_freq) {noTone(rotate_cw_freq);}
}
break;
case CCW:
#ifdef DEBUG_ROTATOR
if (debug_mode) {Serial.print(F("CCW "));Serial.flush();}
#endif //DEBUG_ROTATOR
if (rotation_action == ACTIVATE) {
#ifdef DEBUG_ROTATOR
if (debug_mode) {Serial.println(F("ACTIVATE"));Serial.flush();}
#endif //DEBUG_ROTATOR
brake_release(AZ, BRAKE_RELEASE_ON);
if (az_slowstart_active) {
if (rotate_cw_pwm) {analogWrite(rotate_cw_pwm,0);digitalWrite(rotate_cw_pwm,LOW);}
if (rotate_ccw_pwm) {analogWrite(rotate_ccw_pwm,0);}
if (rotate_cw_ccw_pwm) {analogWrite(rotate_cw_ccw_pwm,0);}
if (rotate_cw_freq) {noTone(rotate_cw_freq);}
if (rotate_ccw_freq) {noTone(rotate_ccw_freq);}
} else {
if (rotate_cw_pwm) {analogWrite(rotate_cw_pwm,0);digitalWrite(rotate_cw_pwm,LOW);}
if (rotate_ccw_pwm) {analogWrite(rotate_ccw_pwm,normal_az_speed_voltage);}
if (rotate_cw_ccw_pwm) {analogWrite(rotate_cw_ccw_pwm,normal_az_speed_voltage);}
if (rotate_cw_freq) {noTone(rotate_cw_freq);}
if (rotate_ccw_freq) {tone(rotate_ccw_freq,map(normal_az_speed_voltage,0,255,AZ_VARIABLE_FREQ_OUTPUT_LOW,AZ_VARIABLE_FREQ_OUTPUT_HIGH));}
}
if (rotate_cw) {digitalWrite(rotate_cw,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_ccw) {digitalWrite(rotate_ccw,ROTATE_PIN_ACTIVE_VALUE);}
#ifdef DEBUG_ROTATOR
if (debug_mode) {
Serial.print(F("rotator: normal_az_speed_voltage:"));
Serial.println(normal_az_speed_voltage);
Serial.flush();
}
#endif //DEBUG_ROTATOR
} else {
#ifdef DEBUG_ROTATOR
if (debug_mode) {Serial.println(F("DEACTIVATE"));Serial.flush();}
#endif //DEBUG_ROTATOR
if (rotate_ccw_pwm) {analogWrite(rotate_ccw_pwm,0);digitalWrite(rotate_ccw_pwm,LOW);}
if (rotate_ccw) {digitalWrite(rotate_ccw,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_ccw_freq) {noTone(rotate_ccw_freq);}
}
break;
#ifdef FEATURE_ELEVATION_CONTROL
//TODO: add pwm and freq pins
case UP:
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.print(F("ROTATION_UP "));Serial.flush(); }
#endif //DEBUG_ROTATOR
if (rotation_action == ACTIVATE) {
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.println(F("ACTIVATE"));Serial.flush(); }
#endif //DEBUG_ROTATOR
brake_release(EL, BRAKE_RELEASE_ON);
if (el_slowstart_active) {
if (rotate_up_pwm) {analogWrite(rotate_up_pwm,0);}
if (rotate_down_pwm) {analogWrite(rotate_down_pwm,0);digitalWrite(rotate_down_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,0);}
if (rotate_up_freq) {noTone(rotate_up_freq);}
if (rotate_down_freq) {noTone(rotate_down_freq);}
} else {
if (rotate_up_pwm) {analogWrite(rotate_up_pwm,normal_el_speed_voltage);}
if (rotate_down_pwm) {analogWrite(rotate_down_pwm,0);digitalWrite(rotate_down_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,normal_el_speed_voltage);}
if (rotate_up_freq) {tone(rotate_up_freq,map(normal_el_speed_voltage,0,255,EL_VARIABLE_FREQ_OUTPUT_LOW,EL_VARIABLE_FREQ_OUTPUT_HIGH));}
if (rotate_down_freq) {noTone(rotate_down_freq);}
}
if (rotate_up) {digitalWrite(rotate_up,ROTATE_PIN_ACTIVE_VALUE);}
if (rotate_down) {digitalWrite(rotate_down,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_up_or_down) {digitalWrite(rotate_up_or_down,ROTATE_PIN_ACTIVE_VALUE);}
} else {
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.println(F("DEACTIVATE"));Serial.flush(); }
#endif //DEBUG_ROTATOR
if (rotate_up) {digitalWrite(rotate_up,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_up_pwm) {analogWrite(rotate_up_pwm,0);digitalWrite(rotate_up_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,0);}
if (rotate_up_freq) {noTone(rotate_up_freq);}
if (rotate_up_or_down) {digitalWrite(rotate_up_or_down,ROTATE_PIN_INACTIVE_VALUE);}
}
break;
case DOWN:
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.print(F("ROTATION_DOWN ")); Serial.flush();}
#endif //DEBUG_ROTATOR
if (rotation_action == ACTIVATE) {
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.println(F("ACTIVATE"));Serial.flush(); }
#endif //DEBUG_ROTATOR
brake_release(EL, BRAKE_RELEASE_ON);
if (el_slowstart_active) {
if (rotate_down_pwm) {analogWrite(rotate_down_pwm,0);}
if (rotate_up_pwm) {analogWrite(rotate_up_pwm,0);digitalWrite(rotate_up_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,0);}
if (rotate_up_freq) {noTone(rotate_up_freq);}
if (rotate_down_freq) {noTone(rotate_down_freq);}
} else {
if (rotate_down_pwm) {analogWrite(rotate_down_pwm,normal_el_speed_voltage);}
if (rotate_up_pwm) {analogWrite(rotate_up_pwm,0);digitalWrite(rotate_up_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,normal_el_speed_voltage);}
if (rotate_down_freq) {tone(rotate_down_freq,map(normal_el_speed_voltage,0,255,EL_VARIABLE_FREQ_OUTPUT_LOW,EL_VARIABLE_FREQ_OUTPUT_HIGH));}
if (rotate_up_freq) {noTone(rotate_up_freq);}
}
if (rotate_up) {digitalWrite(rotate_up,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_down) {digitalWrite(rotate_down,ROTATE_PIN_ACTIVE_VALUE);}
if (rotate_up_or_down) {digitalWrite(rotate_up_or_down,ROTATE_PIN_ACTIVE_VALUE);}
} else {
#ifdef DEBUG_ROTATOR
if (debug_mode) { Serial.println(F("DEACTIVATE"));Serial.flush(); }
#endif //DEBUG_ROTATOR
if (rotate_down) {digitalWrite(rotate_down,ROTATE_PIN_INACTIVE_VALUE);}
if (rotate_down_pwm) {analogWrite(rotate_down_pwm,0);digitalWrite(rotate_down_pwm,LOW);}
if (rotate_up_down_pwm) {analogWrite(rotate_up_down_pwm,0);}
if (rotate_down_freq) {noTone(rotate_down_freq);}
if (rotate_up_or_down) {digitalWrite(rotate_up_or_down,ROTATE_PIN_INACTIVE_VALUE);}
}
break;
#endif //FEATURE_ELEVATION_CONTROL
}
#ifdef DEBUG_ROTATOR
if (debug_mode) {
Serial.println(F("rotator: exiting"));
Serial.flush();
}
#endif //DEBUG_ROTATOR
}
//--------------------------------------------------------------
void initialize_interrupts(){
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
attachInterrupt(AZ_POSITION_PULSE_PIN_INTERRUPT, az_position_pulse_interrupt_handler, FALLING);
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
attachInterrupt(EL_POSITION_PULSE_PIN_INTERRUPT, el_position_pulse_interrupt_handler, FALLING);
#endif //FEATURE_EL_POSITION_PULSE_INPUT
}
//--------------------------------------------------------------
void initialize_pins(){
if (serial_led) {
pinMode(serial_led, OUTPUT);
}
if (overlap_led) {
pinMode(overlap_led, OUTPUT);
}
if (brake_az) {
pinMode(brake_az, OUTPUT);
digitalWrite(brake_az, LOW);
}
if (az_speed_pot) {
pinMode(az_speed_pot, INPUT);
digitalWrite(az_speed_pot, LOW);
}
if (az_preset_pot) {
pinMode(az_preset_pot, INPUT);
digitalWrite(az_preset_pot, LOW);
}
if (preset_start_button) {
pinMode(preset_start_button, INPUT);
digitalWrite(preset_start_button, HIGH);
}
if (button_stop) {
pinMode(button_stop, INPUT);
digitalWrite(button_stop, HIGH);
}
#ifdef FEATURE_ELEVATION_CONTROL
if (brake_el) {
pinMode(brake_el, OUTPUT);
digitalWrite(brake_el, LOW);
}
#endif //FEATURE_ELEVATION_CONTROL
if (rotate_cw) {pinMode(rotate_cw, OUTPUT);}
if (rotate_ccw) {pinMode(rotate_ccw, OUTPUT);}
if (rotate_cw_pwm) {pinMode(rotate_cw_pwm, OUTPUT);}
if (rotate_ccw_pwm) {pinMode(rotate_ccw_pwm, OUTPUT);}
if (rotate_cw_ccw_pwm) {pinMode(rotate_cw_ccw_pwm, OUTPUT);}
if (rotate_cw_freq) {pinMode(rotate_cw_freq, OUTPUT);}
if (rotate_ccw_freq) {pinMode(rotate_ccw_freq, OUTPUT);}
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
#ifndef FEATURE_AZ_POSITION_HMC5883L
pinMode(rotator_analog_az, INPUT);
#endif
if (button_cw) {
pinMode(button_cw, INPUT);
digitalWrite(button_cw, HIGH);
}
if (button_ccw) {
pinMode(button_ccw, INPUT);
digitalWrite(button_ccw, HIGH);
}
normal_az_speed_voltage = PWM_SPEED_VOLTAGE_X4;
current_az_speed_voltage = PWM_SPEED_VOLTAGE_X4;
if (azimuth_speed_voltage) { // if azimuth_speed_voltage pin is configured, set it up for PWM output
analogWrite(azimuth_speed_voltage, PWM_SPEED_VOLTAGE_X4);
}
#ifdef FEATURE_ELEVATION_CONTROL
pinMode(rotate_up, OUTPUT);
pinMode(rotate_down, OUTPUT);
if (rotate_up_or_down) {pinMode(rotate_up_or_down, OUTPUT);}
if (rotate_up_pwm) {pinMode(rotate_up_pwm, OUTPUT);}
if (rotate_down_pwm) {pinMode(rotate_down_pwm, OUTPUT);}
if (rotate_up_down_pwm) {pinMode(rotate_up_down_pwm, OUTPUT);}
if (rotate_up_freq) {pinMode(rotate_up_freq, OUTPUT);}
if (rotate_down_freq) {pinMode(rotate_down_freq, OUTPUT);}
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
#ifdef FEATURE_EL_POSITION_POTENTIOMETER
pinMode(rotator_analog_el, INPUT);
#endif //FEATURE_EL_POSITION_POTENTIOMETER
if (button_up) {
pinMode(button_up, INPUT);
digitalWrite(button_up, HIGH);
}
if (button_down) {
pinMode(button_down, INPUT);
digitalWrite(button_down, HIGH);
}
if (elevation_speed_voltage) { // if elevation_speed_voltage pin is configured, set it up for PWM output
analogWrite(elevation_speed_voltage, PWM_SPEED_VOLTAGE_X4);
normal_el_speed_voltage = PWM_SPEED_VOLTAGE_X4;
current_el_speed_voltage = PWM_SPEED_VOLTAGE_X4;
}
read_elevation();
#endif //FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
if (az_position_pulse_pin) {
pinMode(az_position_pulse_pin, INPUT);
#ifdef OPTION_POSITION_PULSE_INPUT_PULLUPS
digitalWrite(az_position_pulse_pin, HIGH);
#endif //OPTION_POSITION_PULSE_INPUT_PULLUPS
}
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
if (el_position_pulse_pin) {
pinMode(el_position_pulse_pin, INPUT);
#ifdef OPTION_POSITION_PULSE_INPUT_PULLUPS
digitalWrite(el_position_pulse_pin, HIGH);
#endif //OPTION_POSITION_PULSE_INPUT_PULLUPS
}
#endif //FEATURE_EL_POSITION_PULSE_INPUT
#ifdef FEATURE_PARK
if (button_park){
pinMode(button_park, INPUT);
digitalWrite(button_park, HIGH);
}
#endif //FEATURE_PARK
#ifdef FEATURE_ROTATION_INDICATOR_PIN
if (rotation_indication_pin){
pinMode(rotation_indication_pin, OUTPUT);
digitalWrite(rotation_indication_pin,ROTATION_INDICATOR_PIN_INACTIVE_STATE);
}
#endif //FEATURE_ROTATION_INDICATOR_PIN
if (blink_led) {pinMode(blink_led,OUTPUT);}
}
//--------------------------------------------------------------
void initialize_serial(){
Serial.begin(SERIAL_BAUD_RATE);
#ifdef FEATURE_REMOTE_UNIT_SLAVE
Serial.print(F("CS"));
Serial.println(CODE_VERSION);
#endif //FEATURE_REMOTE_UNIT_SLAVE
#ifdef OPTION_SERIAL1_SUPPORT
Serial1.begin(SERIAL1_BAUD_RATE);
#endif //OPTION_SERIAL1_SUPPORT
#ifdef OPTION_SERIAL2_SUPPORT
Serial1.begin(SERIAL2_BAUD_RATE);
#endif //OPTION_SERIAL2_SUPPORT
#ifdef OPTION_SERIAL2_SUPPORT
Serial1.begin(SERIAL2_BAUD_RATE);
#endif //OPTION_SERIAL2_SUPPORT
}
//--------------------------------------------------------------
#ifdef FEATURE_LCD_DISPLAY
void initialize_display(){
#ifndef OPTION_INITIALIZE_YOURDUINO_I2C
lcd.begin(LCD_COLUMNS, 2);
#endif
#ifdef OPTION_INITIALIZE_YOURDUINO_I2C
lcd.begin (16,2);
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(LED_ON);
#endif //OPTION_INITIALIZE_YOURDUINO_I2C
#ifdef FEATURE_I2C_LCD
lcd.setBacklight(lcdcolor);
#endif //FEATURE_I2C_LCD
lcd.setCursor(((LCD_COLUMNS-4)/2),0);
lcd.print("K3NG");
if (LCD_COLUMNS < 20) {
lcd.setCursor(((LCD_COLUMNS-15)/2),1); // W3SA
} else {
lcd.setCursor(((LCD_COLUMNS-18)/2),1);
}
lcd.print("Rotor Controller");
last_lcd_update = millis();
}
#endif
//--------------------------------------------------------------
void initialize_peripherals(){
#ifdef FEATURE_WIRE_SUPPORT
Wire.begin();
#endif
#ifdef FEATURE_AZ_POSITION_HMC5883L
compass = HMC5883L();
int error;
error = compass.SetScale(1.3); //Set the scale of the compass.
if (error != 0) {
Serial.print(F("setup: compass error:"));
Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}
error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
if (error != 0) {
Serial.print(F("setup: compass error:"));
Serial.println(compass.GetErrorText(error)); //check if there is an error, and print if so
}
#endif //FEATURE_AZ_POSITION_HMC5883L
#ifdef FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB
accel = ADXL345();
accel.SetRange(2, true);
accel.EnableMeasurements();
#endif //FEATURE_EL_POSITION_ADXL345_USING_LOVE_ELECTRON_LIB
#ifdef FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB
accel.begin();
#endif //FEATURE_EL_POSITION_ADXL345_USING_ADAFRUIT_LIB
#ifdef FEATURE_JOYSTICK_CONTROL
pinMode(pin_joystick_x,INPUT);
pinMode(pin_joystick_y,INPUT);
#endif //FEATURE_JOYSTICK_CONTROL
#if defined(FEATURE_EL_POSITION_LSM303) || defined(FEATURE_AZ_POSITION_LSM303)
if (!lsm.begin()){
Serial.println(F("setup: LSM303 error"));
}
#endif //FEATURE_EL_POSITION_LSM303 || FEATURE_AZ_POSITION_LSM303
}
//--------------------------------------------------------------
void submit_request(byte axis, byte request, int parm){
#ifdef DEBUG_SUBMIT_REQUEST
if (debug_mode) {Serial.print(F("submit_request: "));}
#endif //DEBUG_SUBMIT_REQUEST
if (axis == AZ) {
#ifdef DEBUG_SUBMIT_REQUEST
if (debug_mode) {Serial.print(F("AZ "));Serial.print(request);Serial.print(F(" "));Serial.println(parm);}
#endif //DEBUG_SUBMIT_REQUEST
az_request = request;
az_request_parm = parm;
az_request_queue_state = IN_QUEUE;
}
#ifdef FEATURE_ELEVATION_CONTROL
if (axis == EL) {
#ifdef DEBUG_SUBMIT_REQUEST
if (debug_mode) {Serial.print(F("EL "));Serial.print(request);Serial.print(F(" "));Serial.println(parm);}
#endif //DEBUG_SUBMIT_REQUEST
el_request = request;
el_request_parm = parm;
el_request_queue_state = IN_QUEUE;
}
#endif //FEATURE_ELEVATION_CONTROL
}
//--------------------------------------------------------------
void service_rotation(){
static byte az_direction_change_flag = 0;
static byte az_initial_slow_down_voltage = 0;
#ifdef FEATURE_ELEVATION_CONTROL
static byte el_direction_change_flag = 0;
static byte el_initial_slow_down_voltage = 0;
#endif //FEATURE_ELEVATION_CONTROL
if (az_state == INITIALIZE_NORMAL_CW) {
update_az_variable_outputs(normal_az_speed_voltage);
rotator(ACTIVATE,CW);
az_state = NORMAL_CW;
}
if (az_state == INITIALIZE_NORMAL_CCW) {
update_az_variable_outputs(normal_az_speed_voltage);
rotator(ACTIVATE,CCW);
az_state = NORMAL_CCW;
}
if (az_state == INITIALIZE_SLOW_START_CW){
update_az_variable_outputs(AZ_SLOW_START_STARTING_PWM);
rotator(ACTIVATE,CW);
az_slowstart_start_time = millis();
az_last_step_time = 0;
az_slow_start_step = 0;
az_state = SLOW_START_CW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: INITIALIZE_SLOW_START_CW -> SLOW_START_CW"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (az_state == INITIALIZE_SLOW_START_CCW){
update_az_variable_outputs(AZ_SLOW_START_STARTING_PWM);
rotator(ACTIVATE,CCW);
az_slowstart_start_time = millis();
az_last_step_time = 0;
az_slow_start_step = 0;
az_state = SLOW_START_CCW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: INITIALIZE_SLOW_START_CCW -> SLOW_START_CCW"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (az_state == INITIALIZE_TIMED_SLOW_DOWN_CW) {
az_direction_change_flag = 0;
az_timed_slow_down_start_time = millis();
az_last_step_time = millis();
az_slow_down_step = AZ_SLOW_DOWN_STEPS-1;
az_state = TIMED_SLOW_DOWN_CW;
}
if (az_state == INITIALIZE_TIMED_SLOW_DOWN_CCW) {
az_direction_change_flag = 0;
az_timed_slow_down_start_time = millis();
az_last_step_time = millis();
az_slow_down_step = AZ_SLOW_DOWN_STEPS-1;
az_state = TIMED_SLOW_DOWN_CCW;
}
if (az_state == INITIALIZE_DIR_CHANGE_TO_CW) {
az_direction_change_flag = 1;
az_timed_slow_down_start_time = millis();
az_last_step_time = millis();
az_slow_down_step = AZ_SLOW_DOWN_STEPS-1;
az_state = TIMED_SLOW_DOWN_CCW;
}
if (az_state == INITIALIZE_DIR_CHANGE_TO_CCW) {
az_direction_change_flag = 1;
az_timed_slow_down_start_time = millis();
az_last_step_time = millis();
az_slow_down_step = AZ_SLOW_DOWN_STEPS-1;
az_state = TIMED_SLOW_DOWN_CW;
}
// slow start-------------------------------------------------------------------------------------------------
if ((az_state == SLOW_START_CW) || (az_state == SLOW_START_CCW)) {
if ((millis() - az_slowstart_start_time) >= AZ_SLOW_START_UP_TIME) { // is it time to end slow start?
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.print(F("service_rotation: NORMAL_C"));}
#endif //DEBUG_SERVICE_ROTATION
if (az_state == SLOW_START_CW) {
az_state = NORMAL_CW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("W"));}
#endif //DEBUG_SERVICE_ROTATION
} else {
az_state = NORMAL_CCW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("CW"));}
#endif //DEBUG_SERVICE_ROTATION
}
update_az_variable_outputs(normal_az_speed_voltage);
} else { // it's not time to end slow start yet, but let's check if it's time to step up the speed voltage
if (((millis() - az_last_step_time) > (AZ_SLOW_START_UP_TIME/AZ_SLOW_START_STEPS)) && (normal_az_speed_voltage > AZ_SLOW_START_STARTING_PWM)){
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: step up: "));
Serial.print(az_slow_start_step);
Serial.print(F(" pwm: "));
Serial.println((int)(AZ_SLOW_START_STARTING_PWM+((normal_az_speed_voltage-AZ_SLOW_START_STARTING_PWM)*((float)az_slow_start_step/(float)(AZ_SLOW_START_STEPS-1)))));
}
#endif //DEBUG_SERVICE_ROTATION
update_az_variable_outputs((AZ_SLOW_START_STARTING_PWM+((normal_az_speed_voltage-AZ_SLOW_START_STARTING_PWM)*((float)az_slow_start_step/(float)(AZ_SLOW_START_STEPS-1)))));
az_last_step_time = millis();
az_slow_start_step++;
}
}
} //((az_state == SLOW_START_CW) || (az_state == SLOW_START_CCW))
// timed slow down ------------------------------------------------------------------------------------------------------
if (((az_state == TIMED_SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CCW)) && ((millis() - az_last_step_time) >= (TIMED_SLOW_DOWN_TIME/AZ_SLOW_DOWN_STEPS))) {
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: TIMED_SLOW_DOWN step down: "));
Serial.print(az_slow_down_step);
Serial.print(F(" pwm: "));
Serial.println((int)(normal_az_speed_voltage*((float)az_slow_down_step/(float)AZ_SLOW_DOWN_STEPS)));
}
#endif //DEBUG_SERVICE_ROTATION
update_az_variable_outputs((int)(normal_az_speed_voltage*((float)az_slow_down_step/(float)AZ_SLOW_DOWN_STEPS)));
az_last_step_time = millis();
az_slow_down_step--;
if (az_slow_down_step == 0) { // is it time to exit timed slow down?
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: TIMED_SLOW_DOWN->IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
if (az_direction_change_flag) {
if (az_state == TIMED_SLOW_DOWN_CW) {
rotator(ACTIVATE,CCW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CCW;} else {az_state = NORMAL_CCW;};
az_direction_change_flag = 0;
}
if (az_state == TIMED_SLOW_DOWN_CCW) {
rotator(ACTIVATE,CW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CW;} else {az_state = NORMAL_CW;};
az_direction_change_flag = 0;
}
} else {
az_state = IDLE;
az_request_queue_state = NONE;
}
}
} //((az_state == TIMED_SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CCW))
// slow down ---------------------------------------------------------------------------------------------------------------
if ((az_state == SLOW_DOWN_CW) || (az_state == SLOW_DOWN_CCW)) {
// is it time to do another step down?
if (abs((target_raw_azimuth - raw_azimuth)/HEADING_MULTIPLIER) <= (((float)SLOW_DOWN_BEFORE_TARGET_AZ*((float)az_slow_down_step/(float)AZ_SLOW_DOWN_STEPS)))){
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: step down: "));
Serial.print(az_slow_down_step);
Serial.print(F(" pwm: "));
Serial.println((int)(AZ_SLOW_DOWN_PWM_STOP+((az_initial_slow_down_voltage-AZ_SLOW_DOWN_PWM_STOP)*((float)az_slow_down_step/(float)AZ_SLOW_DOWN_STEPS))));
}
#endif //DEBUG_SERVICE_ROTATION
update_az_variable_outputs((AZ_SLOW_DOWN_PWM_STOP+((az_initial_slow_down_voltage-AZ_SLOW_DOWN_PWM_STOP)*((float)az_slow_down_step/(float)AZ_SLOW_DOWN_STEPS))));
az_slow_down_step--;
}
} //((az_state == SLOW_DOWN_CW) || (az_state == SLOW_DOWN_CCW))
// normal -------------------------------------------------------------------------------------------------------------------
// if slow down is enabled, see if we're ready to go into slowdown
if (((az_state == NORMAL_CW) || (az_state == SLOW_START_CW) || (az_state == NORMAL_CCW) || (az_state == SLOW_START_CCW)) &&
(az_request_queue_state == IN_PROGRESS_TO_TARGET) && az_slowdown_active && (abs((target_raw_azimuth - raw_azimuth)/HEADING_MULTIPLIER) <= SLOW_DOWN_BEFORE_TARGET_AZ)) {
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.print(F("service_rotation: SLOW_DOWN_C"));}
#endif //DEBUG_SERVICE_ROTATION
az_slow_down_step = AZ_SLOW_DOWN_STEPS-1;
if ((az_state == NORMAL_CW) || (az_state == SLOW_START_CW)){
az_state = SLOW_DOWN_CW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("W"));}
#endif //DEBUG_SERVICE_ROTATION
} else {
az_state = SLOW_DOWN_CCW;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("CW"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (AZ_SLOW_DOWN_PWM_START < current_az_speed_voltage) {
update_az_variable_outputs(AZ_SLOW_DOWN_PWM_START);
az_initial_slow_down_voltage = AZ_SLOW_DOWN_PWM_START;
} else {
az_initial_slow_down_voltage = current_az_speed_voltage;
}
}
// check rotation target --------------------------------------------------------------------------------------------------------
if ((az_state != IDLE) && (az_request_queue_state == IN_PROGRESS_TO_TARGET) ) {
if ((az_state == NORMAL_CW) || (az_state == SLOW_START_CW) || (az_state == SLOW_DOWN_CW)){
if ((abs(raw_azimuth - target_raw_azimuth) < (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER)) || ((raw_azimuth > target_raw_azimuth) && ((raw_azimuth - target_raw_azimuth) < ((AZIMUTH_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
delay(50);
read_azimuth();
if ((abs(raw_azimuth - target_raw_azimuth) < (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER)) || ((raw_azimuth > target_raw_azimuth) && ((raw_azimuth - target_raw_azimuth) < ((AZIMUTH_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
}
}
} else {
if ((abs(raw_azimuth - target_raw_azimuth) < (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER)) || ((raw_azimuth < target_raw_azimuth) && ((target_raw_azimuth - raw_azimuth) < ((AZIMUTH_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
delay(50);
read_azimuth();
if ((abs(raw_azimuth - target_raw_azimuth) < (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER)) || ((raw_azimuth < target_raw_azimuth) && ((target_raw_azimuth - raw_azimuth) < ((AZIMUTH_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
}
}
}
}
#ifdef FEATURE_ELEVATION_CONTROL
if (el_state == INITIALIZE_NORMAL_UP) {
update_el_variable_outputs(normal_el_speed_voltage);
rotator(ACTIVATE,UP);
el_state = NORMAL_UP;
}
if (el_state == INITIALIZE_NORMAL_DOWN) {
update_el_variable_outputs(normal_el_speed_voltage);
rotator(ACTIVATE,DOWN);
el_state = NORMAL_DOWN;
}
if (el_state == INITIALIZE_SLOW_START_UP){
update_el_variable_outputs(EL_SLOW_START_STARTING_PWM);
rotator(ACTIVATE,UP);
el_slowstart_start_time = millis();
el_last_step_time = 0;
el_slow_start_step = 0;
el_state = SLOW_START_UP;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: INITIALIZE_SLOW_START_UP -> SLOW_START_UP"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (el_state == INITIALIZE_SLOW_START_DOWN){
update_el_variable_outputs(EL_SLOW_START_STARTING_PWM);
rotator(ACTIVATE,DOWN);
el_slowstart_start_time = millis();
el_last_step_time = 0;
el_slow_start_step = 0;
el_state = SLOW_START_DOWN;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: INITIALIZE_SLOW_START_DOWN -> SLOW_START_DOWN"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (el_state == INITIALIZE_TIMED_SLOW_DOWN_UP) {
el_direction_change_flag = 0;
el_timed_slow_down_start_time = millis();
el_last_step_time = millis();
el_slow_down_step = EL_SLOW_DOWN_STEPS-1;
el_state = TIMED_SLOW_DOWN_UP;
}
if (el_state == INITIALIZE_TIMED_SLOW_DOWN_DOWN) {
el_direction_change_flag = 0;
el_timed_slow_down_start_time = millis();
el_last_step_time = millis();
el_slow_down_step = EL_SLOW_DOWN_STEPS-1;
el_state = TIMED_SLOW_DOWN_DOWN;
}
if (el_state == INITIALIZE_DIR_CHANGE_TO_UP) {
el_direction_change_flag = 1;
el_timed_slow_down_start_time = millis();
el_last_step_time = millis();
el_slow_down_step = EL_SLOW_DOWN_STEPS-1;
el_state = TIMED_SLOW_DOWN_DOWN;
}
if (el_state == INITIALIZE_DIR_CHANGE_TO_DOWN) {
el_direction_change_flag = 1;
el_timed_slow_down_start_time = millis();
el_last_step_time = millis();
el_slow_down_step = EL_SLOW_DOWN_STEPS-1;
el_state = TIMED_SLOW_DOWN_UP;
}
// slow start-------------------------------------------------------------------------------------------------
if ((el_state == SLOW_START_UP) || (el_state == SLOW_START_DOWN)) {
if ((millis() - el_slowstart_start_time) >= EL_SLOW_START_UP_TIME) { // is it time to end slow start?
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.print(F("service_rotation: NORMAL_"));}
#endif //DEBUG_SERVICE_ROTATION
if (el_state == SLOW_START_UP) {
el_state = NORMAL_UP;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("UP"));}
#endif //DEBUG_SERVICE_ROTATION
} else {
el_state = NORMAL_DOWN;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("DOWN"));}
#endif //DEBUG_SERVICE_ROTATION
}
update_el_variable_outputs(normal_el_speed_voltage);
} else { // it's not time to end slow start yet, but let's check if it's time to step up the speed voltage
if (((millis() - el_last_step_time) > (EL_SLOW_START_UP_TIME/EL_SLOW_START_STEPS)) && (normal_el_speed_voltage > EL_SLOW_START_STARTING_PWM)){
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: step up: "));
Serial.print(el_slow_start_step);
Serial.print(F(" pwm: "));
Serial.println((int)(EL_SLOW_START_STARTING_PWM+((normal_el_speed_voltage-EL_SLOW_START_STARTING_PWM)*((float)el_slow_start_step/(float)(EL_SLOW_START_STEPS-1)))));
}
#endif //DEBUG_SERVICE_ROTATION
update_el_variable_outputs((EL_SLOW_START_STARTING_PWM+((normal_el_speed_voltage-EL_SLOW_START_STARTING_PWM)*((float)el_slow_start_step/(float)(EL_SLOW_START_STEPS-1)))));
el_last_step_time = millis();
el_slow_start_step++;
}
}
} //((el_state == SLOW_START_UP) || (el_state == SLOW_START_DOWN))
// timed slow down ------------------------------------------------------------------------------------------------------
if (((el_state == TIMED_SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_DOWN)) && ((millis() - el_last_step_time) >= (TIMED_SLOW_DOWN_TIME/EL_SLOW_DOWN_STEPS))) {
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: TIMED_SLOW_DOWN step down: "));
Serial.print(el_slow_down_step);
Serial.print(F(" pwm: "));
Serial.println((int)(normal_el_speed_voltage*((float)el_slow_down_step/(float)EL_SLOW_DOWN_STEPS)));
}
#endif //DEBUG_SERVICE_ROTATION
update_el_variable_outputs((int)(normal_el_speed_voltage*((float)el_slow_down_step/(float)EL_SLOW_DOWN_STEPS)));
el_last_step_time = millis();
el_slow_down_step--;
if (el_slow_down_step == 0) { // is it time to exit timed slow down?
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: TIMED_SLOW_DOWN->IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
if (el_direction_change_flag) {
if (el_state == TIMED_SLOW_DOWN_UP) {
rotator(ACTIVATE,DOWN);
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_DOWN;} else {el_state = NORMAL_DOWN;};
el_direction_change_flag = 0;
}
if (el_state == TIMED_SLOW_DOWN_DOWN) {
rotator(ACTIVATE,UP);
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_UP;} else {el_state = NORMAL_UP;};
el_direction_change_flag = 0;
}
} else {
el_state = IDLE;
el_request_queue_state = NONE;
}
}
} //((el_state == TIMED_SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_DOWN))
// slow down ---------------------------------------------------------------------------------------------------------------
if ((el_state == SLOW_DOWN_UP) || (el_state == SLOW_DOWN_DOWN)) {
// is it time to do another step down?
if (abs((target_elevation - elevation)/HEADING_MULTIPLIER) <= (((float)SLOW_DOWN_BEFORE_TARGET_EL*((float)el_slow_down_step/(float)EL_SLOW_DOWN_STEPS)))){
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {
Serial.print(F("service_rotation: step down: "));
Serial.print(el_slow_down_step);
Serial.print(F(" pwm: "));
Serial.println((int)(EL_SLOW_DOWN_PWM_STOP+((el_initial_slow_down_voltage-EL_SLOW_DOWN_PWM_STOP)*((float)el_slow_down_step/(float)EL_SLOW_DOWN_STEPS))));
}
#endif //DEBUG_SERVICE_ROTATION
update_el_variable_outputs((EL_SLOW_DOWN_PWM_STOP+((el_initial_slow_down_voltage-EL_SLOW_DOWN_PWM_STOP)*((float)el_slow_down_step/(float)EL_SLOW_DOWN_STEPS))));
el_slow_down_step--;
}
} //((el_state == SLOW_DOWN_UP) || (el_state == SLOW_DOWN_DOWN))
// normal -------------------------------------------------------------------------------------------------------------------
// if slow down is enabled, see if we're ready to go into slowdown
if (((el_state == NORMAL_UP) || (el_state == SLOW_START_UP) || (el_state == NORMAL_DOWN) || (el_state == SLOW_START_DOWN)) &&
(el_request_queue_state == IN_PROGRESS_TO_TARGET) && el_slowdown_active && (abs((target_elevation - elevation)/HEADING_MULTIPLIER) <= SLOW_DOWN_BEFORE_TARGET_EL)) {
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.print(F("service_rotation: SLOW_DOWN_"));}
#endif //DEBUG_SERVICE_ROTATION
el_slow_down_step = EL_SLOW_DOWN_STEPS-1;
if ((el_state == NORMAL_UP) || (el_state == SLOW_START_UP)){
el_state = SLOW_DOWN_UP;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("UP"));}
#endif //DEBUG_SERVICE_ROTATION
} else {
el_state = SLOW_DOWN_DOWN;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("DOWN"));}
#endif //DEBUG_SERVICE_ROTATION
}
if (EL_SLOW_DOWN_PWM_START < current_el_speed_voltage) {
update_el_variable_outputs(EL_SLOW_DOWN_PWM_START);
el_initial_slow_down_voltage = EL_SLOW_DOWN_PWM_START;
} else {
el_initial_slow_down_voltage = current_el_speed_voltage;
}
}
// check rotation target --------------------------------------------------------------------------------------------------------
if ((el_state != IDLE) && (el_request_queue_state == IN_PROGRESS_TO_TARGET) ) {
if ((el_state == NORMAL_UP) || (el_state == SLOW_START_UP) || (el_state == SLOW_DOWN_UP)){
if ((abs(elevation - target_elevation) < (ELEVATION_TOLERANCE*HEADING_MULTIPLIER)) || ((elevation > target_elevation) && ((elevation - target_elevation) < ((ELEVATION_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
delay(50);
read_elevation();
if ((abs(elevation - target_elevation) < (ELEVATION_TOLERANCE*HEADING_MULTIPLIER)) || ((elevation > target_elevation) && ((elevation - target_elevation) < ((ELEVATION_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
el_state = IDLE;
el_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
}
}
} else {
if ((abs(elevation - target_elevation) < (ELEVATION_TOLERANCE*HEADING_MULTIPLIER)) || ((elevation < target_elevation) && ((target_elevation - elevation) < ((ELEVATION_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
delay(50);
read_elevation();
if ((abs(elevation - target_elevation) < (ELEVATION_TOLERANCE*HEADING_MULTIPLIER)) || ((elevation < target_elevation) && ((target_elevation - elevation) < ((ELEVATION_TOLERANCE+5)*HEADING_MULTIPLIER)))) {
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
el_state = IDLE;
el_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_ROTATION
if (debug_mode) {Serial.println(F("service_rotation: IDLE"));}
#endif //DEBUG_SERVICE_ROTATION
}
}
}
}
#endif //FEATURE_ELEVATION_CONTROL
}
//--------------------------------------------------------------
void service_request_queue(){
//xxxx
int work_target_raw_azimuth = 0;
byte direction_to_go = 0;
if (az_request_queue_state == IN_QUEUE) {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("service_request_queue: AZ "));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
switch(az_request){
case(REQUEST_STOP):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_STOP"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (az_state != IDLE){
if (az_slowdown_active) {
if ((az_state == TIMED_SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CCW)) { // if we're already in timed slow down and we get another stop, do a hard stop
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
}
if ((az_state == SLOW_START_CW) || (az_state == NORMAL_CW)) {
az_state = INITIALIZE_TIMED_SLOW_DOWN_CW;
az_request_queue_state = IN_PROGRESS_TIMED;
az_last_rotate_initiation = millis();
}
if ((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW)) {
az_state = INITIALIZE_TIMED_SLOW_DOWN_CCW;
az_request_queue_state = IN_PROGRESS_TIMED;
az_last_rotate_initiation = millis();
}
} else {
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
}
} else {
az_request_queue_state = NONE; // nothing to do - we clear the queue
}
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_STOP
case(REQUEST_AZIMUTH):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_AZIMUTH"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if ((az_request_parm >= 0) && (az_request_parm <= (360*HEADING_MULTIPLIER))) {
target_azimuth = az_request_parm;
target_raw_azimuth = az_request_parm;
if (target_azimuth == (360*HEADING_MULTIPLIER)) {target_azimuth = 0;}
if ((target_azimuth > (azimuth - (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER))) && (target_azimuth < (azimuth + (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER)))) {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" request within tolerance"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else { // target azimuth is not within tolerance, we need to rotate
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" ->A"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
work_target_raw_azimuth = target_azimuth;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {
Serial.print(F(" work_target_raw_azimuth:"));
Serial.print(work_target_raw_azimuth/HEADING_MULTIPLIER);
Serial.print(F(" configuration.azimuth_starting_point:"));
Serial.print(configuration.azimuth_starting_point);
Serial.print(" ");
}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (work_target_raw_azimuth < (configuration.azimuth_starting_point*HEADING_MULTIPLIER)) {
work_target_raw_azimuth = work_target_raw_azimuth + (360*HEADING_MULTIPLIER);
target_raw_azimuth = work_target_raw_azimuth;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->B"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
if ((work_target_raw_azimuth + (360*HEADING_MULTIPLIER)) < ((configuration.azimuth_starting_point + configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER)) { // is there a second possible heading in overlap?
if (abs(raw_azimuth - work_target_raw_azimuth) < abs((work_target_raw_azimuth+(360*HEADING_MULTIPLIER)) - raw_azimuth)) { // is second possible heading closer?
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->C"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (work_target_raw_azimuth > raw_azimuth) { // not closer, use position in non-overlap
direction_to_go = CW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("->CW!"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
direction_to_go = CCW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("->CCW!"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
} else { // go to position in overlap
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->D"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
target_raw_azimuth = work_target_raw_azimuth + (360*HEADING_MULTIPLIER);
if ((work_target_raw_azimuth + (360*HEADING_MULTIPLIER)) > raw_azimuth) {
direction_to_go = CW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->CW!"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
direction_to_go = CCW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->CCW!"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
}
} else { // no possible second heading in overlap
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->E"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (work_target_raw_azimuth > raw_azimuth) {
direction_to_go = CW;
} else {
direction_to_go = CCW;
}
}
}
} else {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("->F"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if ((az_request_parm > (360*HEADING_MULTIPLIER)) && (az_request_parm <= ((configuration.azimuth_starting_point+configuration.azimuth_rotation_capability)*HEADING_MULTIPLIER))) {
target_azimuth = az_request_parm - (360*HEADING_MULTIPLIER);
target_raw_azimuth = az_request_parm;
if (az_request_parm > raw_azimuth) {
direction_to_go = CW;
} else {
direction_to_go = CCW;
}
} else {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {
Serial.print(F(" error: bogus azimuth request:"));
Serial.println(az_request_parm);
}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
return;
}
}
if (direction_to_go == CW){
if (((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != INITIALIZE_SLOW_START_CW) && (az_state != SLOW_START_CW) && (az_state != NORMAL_CW)) { // if we're already rotating CW, don't do anything
//rotator(ACTIVATE,CW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CW;} else {az_state = INITIALIZE_NORMAL_CW;};
}
}
}
if (direction_to_go == CCW){
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CCW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CCW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != INITIALIZE_SLOW_START_CCW) && (az_state != SLOW_START_CCW) && (az_state != NORMAL_CCW)) { // if we're already rotating CCW, don't do anything
//rotator(ACTIVATE,CCW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CCW;} else {az_state = INITIALIZE_NORMAL_CCW;};
}
}
}
az_request_queue_state = IN_PROGRESS_TO_TARGET;
az_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_AZIMUTH
case(REQUEST_AZIMUTH_RAW):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_AZIMUTH_RAW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
target_raw_azimuth = az_request_parm;
target_azimuth = target_raw_azimuth;
if (target_azimuth >= (360*HEADING_MULTIPLIER)) {target_azimuth = target_azimuth - (360*HEADING_MULTIPLIER);}
if (((abs(raw_azimuth - target_raw_azimuth) < (AZIMUTH_TOLERANCE*HEADING_MULTIPLIER))) && (az_state == IDLE)) {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" request within tolerance"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
az_request_queue_state = NONE;
} else {
if (target_raw_azimuth > raw_azimuth) {
if (((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != INITIALIZE_SLOW_START_CW) && (az_state != SLOW_START_CW) && (az_state != NORMAL_CW)) { // if we're already rotating CW, don't do anything
//rotator(ACTIVATE,CW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CW;} else {az_state = INITIALIZE_NORMAL_CW;};
}
}
}
if (target_raw_azimuth < raw_azimuth) {
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CCW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CCW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != INITIALIZE_SLOW_START_CCW) && (az_state != SLOW_START_CCW) && (az_state != NORMAL_CCW)) { // if we're already rotating CCW, don't do anything
// rotator(ACTIVATE,CCW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CCW;} else {az_state = INITIALIZE_NORMAL_CCW;};
}
}
}
az_request_queue_state = IN_PROGRESS_TO_TARGET;
az_last_rotate_initiation = millis();
}
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_AZIMUTH_RAW
case(REQUEST_CW):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_CW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != SLOW_START_CW) && (az_state != NORMAL_CW)) {
//rotator(ACTIVATE,CW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CW;} else {az_state = INITIALIZE_NORMAL_CW;};
}
}
az_request_queue_state = NONE;
az_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_CW
case(REQUEST_CCW):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("REQUEST_CCW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) && (az_slowstart_active)){
az_state = INITIALIZE_DIR_CHANGE_TO_CCW;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F(" INITIALIZE_DIR_CHANGE_TO_CCW"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((az_state != SLOW_START_CCW) && (az_state != NORMAL_CCW)) {
//rotator(ACTIVATE,CCW);
if (az_slowstart_active) {az_state = INITIALIZE_SLOW_START_CCW;} else {az_state = INITIALIZE_NORMAL_CCW;};
}
}
az_request_queue_state = NONE;
az_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_CCW
case(REQUEST_KILL):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_KILL"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
rotator(DEACTIVATE,CW);
rotator(DEACTIVATE,CCW);
az_state = IDLE;
az_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_KILL
}
}
#ifdef FEATURE_ELEVATION_CONTROL
if (el_request_queue_state == IN_QUEUE){
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("service_request_queue: EL "));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
switch(el_request) {
case(REQUEST_ELEVATION):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_ELEVATION "));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
target_elevation = el_request_parm;
if (target_elevation > (ELEVATION_MAXIMUM_DEGREES*HEADING_MULTIPLIER)){
target_elevation = ELEVATION_MAXIMUM_DEGREES * HEADING_MULTIPLIER;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_ELEVATION: target_elevation > ELEVATION_MAXIMUM_DEGREES"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
#ifdef OPTION_EL_MANUAL_ROTATE_LIMITS
if (target_elevation < (EL_MANUAL_ROTATE_DOWN_LIMIT*HEADING_MULTIPLIER)){
target_elevation = EL_MANUAL_ROTATE_DOWN_LIMIT * HEADING_MULTIPLIER;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_ELEVATION: target_elevation < EL_MANUAL_ROTATE_DOWN_LIMIT"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
if (target_elevation > (EL_MANUAL_ROTATE_UP_LIMIT*HEADING_MULTIPLIER)){
target_elevation = EL_MANUAL_ROTATE_UP_LIMIT * HEADING_MULTIPLIER;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.print(F("REQUEST_ELEVATION: target_elevation > EL_MANUAL_ROTATE_UP_LIMIT"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
}
#endif //OPTION_EL_MANUAL_ROTATE_LIMITS
if (abs(target_elevation - elevation) < (ELEVATION_TOLERANCE*HEADING_MULTIPLIER)) {
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("requested elevation within tolerance"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
//el_request_queue_state = NONE;
} else {
if (target_elevation > elevation) {
if (((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) && (el_slowstart_active)){
el_state = INITIALIZE_DIR_CHANGE_TO_UP;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F(" INITIALIZE_DIR_CHANGE_TO_UP"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((el_state != INITIALIZE_SLOW_START_UP) && (el_state != SLOW_START_UP) && (el_state != NORMAL_UP)) { // if we're already rotating UP, don't do anything
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_UP;} else {el_state = INITIALIZE_NORMAL_UP;};
}
}
} //(target_elevation > elevation)
if (target_elevation < elevation) {
if (((el_state == SLOW_START_UP) || (el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (el_slowstart_active)){
el_state = INITIALIZE_DIR_CHANGE_TO_DOWN;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F(" INITIALIZE_DIR_CHANGE_TO_DOWN"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((el_state != INITIALIZE_SLOW_START_DOWN) && (el_state != SLOW_START_DOWN) && (el_state != NORMAL_DOWN)) { // if we're already rotating DOWN, don't do anything
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_DOWN;} else {el_state = INITIALIZE_NORMAL_DOWN;};
}
}
} //(target_elevation < elevation)
} //(abs(target_elevation - elevation) < ELEVATION_TOLERANCE)
el_request_queue_state = IN_PROGRESS_TO_TARGET;
el_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_ELEVATION
case(REQUEST_UP):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("REQUEST_UP"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) && (el_slowstart_active)){
el_state = INITIALIZE_DIR_CHANGE_TO_UP;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("service_request_queue: INITIALIZE_DIR_CHANGE_TO_UP"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((el_state != SLOW_START_UP) && (el_state != NORMAL_UP)) {
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_UP;} else {el_state = INITIALIZE_NORMAL_UP;};
}
}
el_request_queue_state = NONE;
el_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_UP
case(REQUEST_DOWN):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("REQUEST_DOWN"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (((el_state == SLOW_START_UP) || (el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) && (el_slowstart_active)){
el_state = INITIALIZE_DIR_CHANGE_TO_DOWN;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("service_request_queue: INITIALIZE_DIR_CHANGE_TO_DOWN"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
} else {
if ((el_state != SLOW_START_DOWN) && (el_state != NORMAL_DOWN)) {
if (el_slowstart_active) {el_state = INITIALIZE_SLOW_START_DOWN;} else {el_state = INITIALIZE_NORMAL_DOWN;};
}
}
el_request_queue_state = NONE;
el_last_rotate_initiation = millis();
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_DOWN
case(REQUEST_STOP):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("REQUEST_STOP"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
if (el_state != IDLE){
if (el_slowdown_active) {
if ((el_state == TIMED_SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_DOWN)) { // if we're already in timed slow down and we get another stop, do a hard stop
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
el_state = IDLE;
el_request_queue_state = NONE;
}
if ((el_state == SLOW_START_UP) || (el_state == NORMAL_UP)) {
el_state = INITIALIZE_TIMED_SLOW_DOWN_UP;
el_request_queue_state = IN_PROGRESS_TIMED;
el_last_rotate_initiation = millis();
}
if ((el_state == SLOW_START_DOWN) || (el_state == NORMAL_DOWN)) {
el_state = INITIALIZE_TIMED_SLOW_DOWN_DOWN;
el_request_queue_state = IN_PROGRESS_TIMED;
el_last_rotate_initiation = millis();
}
} else {
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
el_state = IDLE;
el_request_queue_state = NONE;
}
} else {
el_request_queue_state = NONE; //nothing to do, we're already in IDLE state
}
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_STOP
case(REQUEST_KILL):
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println(F("REQUEST_KILL"));}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
rotator(DEACTIVATE,UP);
rotator(DEACTIVATE,DOWN);
el_state = IDLE;
el_request_queue_state = NONE;
#ifdef DEBUG_SERVICE_REQUEST_QUEUE
if (debug_mode) {Serial.println();}
#endif //DEBUG_SERVICE_REQUEST_QUEUE
break; //REQUEST_KILL
}
} //(el_request_queue_state == IN_QUEUE)
#endif //FEATURE_ELEVATION_CONTROL
}
//--------------------------------------------------------------
void check_for_dirty_configuration(){
static unsigned long last_config_write_time = 0;
if ((configuration_dirty) && ((millis() - last_config_write_time) > (EEPROM_WRITE_DIRTY_CONFIG_TIME*1000))){
write_settings_to_eeprom();
last_config_write_time = millis();
}
}
//--------------------------------------------------------------
byte current_az_state(){
if ((az_state == SLOW_START_CW) || (az_state == NORMAL_CW) || (az_state == SLOW_DOWN_CW) || (az_state == TIMED_SLOW_DOWN_CW)) {
return ROTATING_CW;
}
if ((az_state == SLOW_START_CCW) || (az_state == NORMAL_CCW) || (az_state == SLOW_DOWN_CCW) || (az_state == TIMED_SLOW_DOWN_CCW)) {
return ROTATING_CCW;
}
return NOT_DOING_ANYTHING;
}
//--------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
byte current_el_state(){
if ((el_state == SLOW_START_UP)||(el_state == NORMAL_UP) || (el_state == SLOW_DOWN_UP) || (el_state == TIMED_SLOW_DOWN_UP)) {
return ROTATING_UP;
}
if ((el_state == SLOW_START_DOWN)||(el_state == NORMAL_DOWN) || (el_state == SLOW_DOWN_DOWN) || (el_state == TIMED_SLOW_DOWN_DOWN)) {
return ROTATING_DOWN;
}
return NOT_DOING_ANYTHING;
}
#endif //FEATURE_ELEVATION_CONTROL
//--------------------------------------------------------------
#ifdef FEATURE_AZ_POSITION_PULSE_INPUT
void az_position_pulse_interrupt_handler(){
//aaaaa
#ifdef DEBUG_POSITION_PULSE_INPUT
//az_position_pule_interrupt_handler_flag++;
az_pulse_counter++;
#endif //DEBUG_POSITION_PULSE_INPUT
if (current_az_state() == ROTATING_CW) {
az_position_pulse_input_azimuth += AZ_POSITION_PULSE_DEG_PER_PULSE;
last_known_az_state = ROTATING_CW;
} else {
if (current_az_state() == ROTATING_CCW) {
az_position_pulse_input_azimuth -= AZ_POSITION_PULSE_DEG_PER_PULSE;
last_known_az_state = ROTATING_CCW;
} else {
if (last_known_az_state == ROTATING_CW){
az_position_pulse_input_azimuth += AZ_POSITION_PULSE_DEG_PER_PULSE;
} else {
if (last_known_az_state == ROTATING_CCW){
az_position_pulse_input_azimuth -= AZ_POSITION_PULSE_DEG_PER_PULSE;
}
}
#ifdef DEBUG_POSITION_PULSE_INPUT
az_pulse_counter_ambiguous++;
#endif //DEBUG_POSITION_PULSE_INPUT
}
}
#ifdef OPTION_AZ_POSITION_PULSE_HARD_LIMIT
if (az_position_pulse_input_azimuth < configuration.azimuth_starting_point) {
az_position_pulse_input_azimuth = configuration.azimuth_starting_point;
}
if (az_position_pulse_input_azimuth > (configuration.azimuth_starting_point + configuration.azimuth_rotation_capability)) {
az_position_pulse_input_azimuth = (configuration.azimuth_starting_point + configuration.azimuth_rotation_capability);
}
#else
if (az_position_pulse_input_azimuth < 0){
az_position_pulse_input_azimuth += 360;
}
if (az_position_pulse_input_azimuth >= 360){
az_position_pulse_input_azimuth -= 360;
}
#endif //OPTION_AZ_POSITION_PULSE_HARD_LIMIT
}
#endif //FEATURE_AZ_POSITION_PULSE_INPUT
//--------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CONTROL
#ifdef FEATURE_EL_POSITION_PULSE_INPUT
void el_position_pulse_interrupt_handler(){
#ifdef DEBUG_POSITION_PULSE_INPUT
//el_position_pule_interrupt_handler_flag++;
el_pulse_counter++;
#endif //DEBUG_POSITION_PULSE_INPUT
if (current_el_state() == ROTATING_UP) {
el_position_pulse_input_elevation += EL_POSITION_PULSE_DEG_PER_PULSE;
last_known_el_state = ROTATING_UP;
} else{
if (current_el_state() == ROTATING_DOWN) {
el_position_pulse_input_elevation -= EL_POSITION_PULSE_DEG_PER_PULSE;
last_known_el_state = ROTATING_DOWN;
} else {
if (last_known_el_state == ROTATING_UP){
el_position_pulse_input_elevation += EL_POSITION_PULSE_DEG_PER_PULSE;
} else {
if (last_known_el_state == ROTATING_DOWN){
el_position_pulse_input_elevation -= EL_POSITION_PULSE_DEG_PER_PULSE;
}
}
#ifdef DEBUG_POSITION_PULSE_INPUT
el_pulse_counter_ambiguous++;
#endif //DEBUG_POSITION_PULSE_INPUT
}
}
#ifdef OPTION_EL_POSITION_PULSE_HARD_LIMIT
if (el_position_pulse_input_elevation < 0){
el_position_pulse_input_elevation = 0;
}
if (el_position_pulse_input_elevation > ELEVATION_MAXIMUM_DEGREES){
el_position_pulse_input_elevation = ELEVATION_MAXIMUM_DEGREES;
}
#endif //OPTION_EL_POSITION_PULSE_HARD_LIMIT
}
#endif //FEATURE_EL_POSITION_PULSE_INPUT
#endif //FEATURE_ELEVATION_CONTROL
//--------------------------------------------------------------------------
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
byte submit_remote_command(byte remote_command_to_send){
if (remote_unit_command_submitted || suspend_remote_commands) {
return 0;
} else {
switch(remote_command_to_send){
case REMOTE_UNIT_AZ_COMMAND:
Serial1.println("AZ");
if (remote_port_tx_sniff) {Serial.println("AZ");}
remote_unit_command_submitted = REMOTE_UNIT_AZ_COMMAND;
break;
case REMOTE_UNIT_EL_COMMAND:
Serial1.println("EL");
if (remote_port_tx_sniff) {Serial.println("EL");}
remote_unit_command_submitted = REMOTE_UNIT_EL_COMMAND;
break;
}
last_remote_unit_command_time = millis();
remote_unit_command_results_available = 0;
return 1;
}
}
#endif //FEATURE_HOST_REMOTE_PROTOCOL
//--------------------------------------------------------------------------
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
byte is_ascii_number(byte char_in){
if ((char_in > 47) && (char_in < 58)) {
return 1;
} else {
return 0;
}
}
#endif //FEATURE_HOST_REMOTE_PROTOCOL
//--------------------------------------------------------------------------
#ifdef FEATURE_HOST_REMOTE_PROTOCOL
void service_remote_communications_incoming_serial_buffer(){
byte good_data = 0;
if (serial1_buffer_carriage_return_flag){
#ifdef DEBUG_SVC_REMOTE_COMM_INCOMING_BUFFER
if (debug_mode){
Serial.print(F("service_remote_communications_incoming_serial_buffer: serial1_buffer_index: "));
Serial.print(serial1_buffer_index);
Serial.print(F(" buffer: "));
for (int x = 0;x < serial1_buffer_index;x++){
Serial.write(serial1_buffer[x]);
}
Serial.println("$");
}
#endif //DEBUG_SVC_REMOTE_COMM_INCOMING_BUFFER
if (remote_unit_command_submitted) { // this was a solicited response
switch(remote_unit_command_submitted){
case REMOTE_UNIT_AZ_COMMAND:
if ((serial1_buffer_index == 7) && (serial1_buffer[0] == 'A') && (serial1_buffer[1] == 'Z') &&
(is_ascii_number(serial1_buffer[2])) && (is_ascii_number(serial1_buffer[3])) && (is_ascii_number(serial1_buffer[4])) && (is_ascii_number(serial1_buffer[5]))){
remote_unit_command_result_float = ((serial1_buffer[2]-48)*100) + ((serial1_buffer[3]-48)*10) + (serial1_buffer[4]-48) + ((serial1_buffer[5]-48)/10.0);
good_data = 1;
}
break;
case REMOTE_UNIT_EL_COMMAND:
if ((serial1_buffer_index == 8) && (serial1_buffer[0] == 'E') && (serial1_buffer[1] == 'L') &&
(is_ascii_number(serial1_buffer[3])) && (is_ascii_number(serial1_buffer[4])) && (is_ascii_number(serial1_buffer[5])) && (is_ascii_number(serial1_buffer[6]))){
remote_unit_command_result_float = ((serial1_buffer[3]-48)*100) + ((serial1_buffer[4]-48)*10) + (serial1_buffer[5]-48) + ((serial1_buffer[6]-48)/10.0);
if (serial1_buffer[2] == '+') {
good_data = 1;
}
if (serial1_buffer[2] == '-') {
remote_unit_command_result_float = remote_unit_command_result_float * -1.0;
good_data = 1;
}
}
break;
}
if (good_data) {
remote_unit_command_results_available = remote_unit_command_submitted;
remote_unit_good_results++;
#ifdef DEBUG_SVC_REMOTE_COMM_INCOMING_BUFFER
if (debug_mode){
Serial.print(F("service_remote_communications_incoming_serial_buffer: remote_unit_command_results_available: "));
Serial.print(remote_unit_command_results_available);
Serial.print(F(" remote_unit_command_result_float: "));
Serial.println(remote_unit_command_result_float);
}
#endif //DEBUG_SVC_REMOTE_COMM_INCOMING_BUFFER
} else {
remote_unit_command_results_available = 0;
remote_unit_bad_results++;
}
remote_unit_command_submitted = 0;
} else { // this was an unsolicited message
}
serial1_buffer_carriage_return_flag = 0;
serial1_buffer_index = 0;
}
// has a command timed out?
if ((remote_unit_command_submitted) && ((millis() - last_remote_unit_command_time) > REMOTE_UNIT_COMMAND_TIMEOUT_MS)){
remote_unit_command_timeouts++;
remote_unit_command_submitted = 0;
serial1_buffer_index = 0;
}
// have characters been in the buffer for some time but no carriage return?
if ((serial1_buffer_index) && (!remote_unit_command_submitted) && ((millis() - serial1_last_receive_time) > REMOTE_UNIT_COMMAND_TIMEOUT_MS)) {
serial1_buffer_index = 0;
remote_unit_incoming_buffer_timeouts++;
}
}
#endif //FEATURE_HOST_REMOTE_PROTOCOL
//--------------------------------------------------------------------------
#ifdef FEATURE_AZIMUTH_CORRECTION
float correct_azimuth(float azimuth_in){
if (sizeof(azimuth_calibration_from) != sizeof(azimuth_calibration_to)){
return azimuth_in;
}
for (unsigned int x = 0;x < (sizeof(azimuth_calibration_from)-2);x++){
if ((azimuth_in >= azimuth_calibration_from[x]) && (azimuth_in <= azimuth_calibration_from[x+1])){
return (map(azimuth_in*10,azimuth_calibration_from[x]*10,azimuth_calibration_from[x+1]*10,azimuth_calibration_to[x]*10,azimuth_calibration_to[x+1]*10))/10.0;
}
}
return(azimuth_in);
}
#endif //FEATURE_AZIMUTH_CORRECTION
//--------------------------------------------------------------------------
#ifdef FEATURE_ELEVATION_CORRECTION
float correct_elevation(float elevation_in){
if (sizeof(elevation_calibration_from) != sizeof(elevation_calibration_to)){
return elevation_in;
}
for (unsigned int x = 0;x < (sizeof(elevation_calibration_from)-2);x++){
if ((elevation_in >= elevation_calibration_from[x]) && (elevation_in <= elevation_calibration_from[x+1])){
return (map(elevation_in*10,elevation_calibration_from[x]*10,elevation_calibration_from[x+1]*10,elevation_calibration_to[x]*10,elevation_calibration_to[x+1]*10))/10.0;
}
}
return(elevation_in);
}
#endif //FEATURE_ELEVATION_CORRECTION
//--------------------------------------------------------------------------
#ifdef FEATURE_JOYSTICK_CONTROL
void check_joystick(){
int joystick_x = 0;
int joystick_y = 0;
static int joystick_resting_x = 0;
static int joystick_resting_y = 0;
//zzzz
static unsigned long last_joystick_az_action_time = 0;
static byte joystick_azimuth_rotation = NOT_DOING_ANYTHING;
#ifdef FEATURE_ELEVATION_CONTROL
static byte joystick_elevation_rotation = NOT_DOING_ANYTHING;
static unsigned long last_joystick_el_action_time = 0;
#endif //FEATURE_ELEVATION_CONTROL
if ((joystick_resting_x == 0) || (joystick_resting_y == 0)) { // initialize the resting readings if this is our first time here
joystick_resting_x = analogRead(pin_joystick_x);
joystick_resting_y = analogRead(pin_joystick_y);
} else {
joystick_x = analogRead(pin_joystick_x);
joystick_y = analogRead(pin_joystick_y);
if ((millis() - last_joystick_az_action_time) > JOYSTICK_WAIT_TIME_MS) {
#ifdef DEBUG_JOYSTICK
static unsigned long last_debug_joystick_status = 0;
if ((debug_mode) && ((millis() - last_debug_joystick_status) > 1000)){
Serial.print("check_joystick: x: ");
Serial.print(joystick_x);
Serial.print("\ty: ");
Serial.println(joystick_y);
last_debug_joystick_status = millis();
}
#endif //DEBUG_JOYSTICK
#ifndef OPTION_JOYSTICK_REVERSE_X_AXIS
if ((joystick_resting_x-joystick_x) < (joystick_resting_x * -0.2)) { // left
#else
if ((joystick_resting_x-joystick_x) > (joystick_resting_x * 0.2)) {
#endif
#ifdef DEBUG_JOYSTICK
if (debug_mode){Serial.println("check_joystick: L");}
#endif //DEBUG_JOYSTICK
if (current_az_state() != ROTATING_CCW) {
submit_request(AZ,REQUEST_CCW,0);
}
joystick_azimuth_rotation = ROTATING_CCW;
last_joystick_az_action_time = millis();
} else {
#ifndef OPTION_JOYSTICK_REVERSE_X_AXIS
if ((joystick_resting_x-joystick_x) > (joystick_resting_x * 0.2)) { // right
#else
if ((joystick_resting_x-joystick_x) < (joystick_resting_x * -0.2)) {
#endif
#ifdef DEBUG_JOYSTICK
if (debug_mode){Serial.println("check_joystick: R");}
#endif //DEBUG_JOYSTICK
if (current_az_state() != ROTATING_CW) {
submit_request(AZ,REQUEST_CW,0);
}
joystick_azimuth_rotation = ROTATING_CW;
last_joystick_az_action_time = millis();
} else { // joystick is in X axis resting position
if (joystick_azimuth_rotation != NOT_DOING_ANYTHING) {
if (current_az_state() != NOT_DOING_ANYTHING) {
submit_request(AZ,REQUEST_STOP,0);
last_joystick_az_action_time = millis();
}
joystick_azimuth_rotation = NOT_DOING_ANYTHING;
}
}
}
}
if ((millis() - last_joystick_el_action_time) > JOYSTICK_WAIT_TIME_MS) {
#ifdef FEATURE_ELEVATION_CONTROL
#ifndef OPTION_JOYSTICK_REVERSE_Y_AXIS
if ((joystick_resting_y-joystick_y) > (joystick_resting_y * 0.2)) { // down
#else
if ((joystick_resting_y-joystick_y) < (joystick_resting_y * -0.2)) {
#endif
#ifdef DEBUG_JOYSTICK
if (debug_mode){Serial.println("check_joystick: D");}
#endif //DEBUG_JOYSTICK
if (current_el_state() != ROTATING_DOWN) {
submit_request(EL,REQUEST_DOWN,0);
}
joystick_elevation_rotation = ROTATING_DOWN;
last_joystick_el_action_time = millis();
} else {
#ifndef OPTION_JOYSTICK_REVERSE_Y_AXIS
if ((joystick_resting_y-joystick_y) < (joystick_resting_y * -0.2)) { // up
#else
if ((joystick_resting_y-joystick_y) > (joystick_resting_y * 0.2)) {
#endif
#ifdef DEBUG_JOYSTICK
if (debug_mode){Serial.println("check_joystick: U");}
#endif //DEBUG_JOYSTICK
if (current_el_state() != ROTATING_UP) {
submit_request(EL,REQUEST_UP,0);
}
joystick_elevation_rotation = ROTATING_UP;
last_joystick_el_action_time = millis();
} else { // Y axis is in resting position
if (joystick_elevation_rotation != NOT_DOING_ANYTHING) {
if (current_el_state() != NOT_DOING_ANYTHING) {
submit_request(EL,REQUEST_STOP,0);
last_joystick_el_action_time = millis();
}
joystick_elevation_rotation = NOT_DOING_ANYTHING;
}
}
}
#endif //FEATURE_ELEVATION_CONTROL
}
}
}
#endif //FEATURE_JOYSTICK_CONTROL
//--------------------------------------------------------------------------
#ifdef FEATURE_ROTATION_INDICATOR_PIN
void service_rotation_indicator_pin(){
static byte rotation_indication_pin_state = 0;
static unsigned long time_rotation_went_inactive = 0;
#ifdef FEATURE_ELEVATION_CONTROL
if ((!rotation_indication_pin_state) && ((az_state != IDLE) || (el_state != IDLE))){
#else
if ((!rotation_indication_pin_state) && ((az_state != IDLE))){
#endif
if (rotation_indication_pin){
digitalWrite(rotation_indication_pin,ROTATION_INDICATOR_PIN_ACTIVE_STATE);
}
rotation_indication_pin_state = 1;
#ifdef DEBUG_ROTATION_INDICATION_PIN
if (debug_mode){Serial.println(F("service_rotation_indicator_pin: active"));}
#endif
}
#ifdef FEATURE_ELEVATION_CONTROL
if ((rotation_indication_pin_state) && (az_state == IDLE) && (el_state == IDLE)){
#else
if ((rotation_indication_pin_state) && (az_state == IDLE)){
#endif
if (time_rotation_went_inactive == 0){
time_rotation_went_inactive = millis();
} else {
if ((millis() - time_rotation_went_inactive) >= ((ROTATION_INDICATOR_PIN_TIME_DELAY_SECONDS * 1000)+(ROTATION_INDICATOR_PIN_TIME_DELAY_MINUTES * 60 * 1000))){
if (rotation_indication_pin){
digitalWrite(rotation_indication_pin,ROTATION_INDICATOR_PIN_INACTIVE_STATE);
}
rotation_indication_pin_state = 0;
time_rotation_went_inactive = 0;
#ifdef DEBUG_ROTATION_INDICATION_PIN
if (debug_mode){Serial.println(F("service_rotation_indicator_pin: inactive"));}
#endif
}
}
}
}
#endif //FEATURE_ROTATION_INDICATOR_PIN