#include <SFE_BMP180.h>
#include <avr/wdt.h>
#include <Wire.h>
#include <SPI.h>
#include <LSM303.h> // modified ... fixed a couple of bugs
#include <LiquidCrystal_I2C.h>
#include <L3G.h>
#include "ds3231.h"
#include <TimeLib.h>
#include "ht16k33.h"
#include <ModbusRtu.h> // Modified ... this no longer a stock lib - Slave supports register translation/mapping
#include <EEPROM.h>
#include <math.h>
#include <Ethernet.h>
#include <SD.h>
#include <EthernetUdp.h>
#include <TinyGPS.h>
#include "WiFiEsp.h"
#define ID 1
#define BUFF_MAX 32
#define PARK_EAST 1
#define PARK_WEST 2
#define PARK_NORTH 3
#define PARK_SOUTH 4
#define PARK_FLAT 5
#define MOTOR_DWELL 100
#define MAX_MODBUS_DATA 70
#define HT16K33_DSP_NOBLINK 0 // constants for the half arsed cheapo display
#define HT16K33_DSP_BLINK1HZ 4
#define HT16K33_DSP_BLINK2HZ 2
#define HT16K33_DSP_BLINK05HZ 6
const byte SPARE1 = 2;
const byte FACTORY_RESET = 3;
const byte SPARE2 = 8;
const byte RELAY_YZ_DIR = 8; // DIR 1 Y+ Y- East / West Was the X+ N relay BROWN
const byte RELAY_YZ_PWM = 7; // PWM 2 Speed East / West Was the Y- E relay ORANGE
const byte RELAY_XZ_PWM = 6; // PWM 2 Speed North / South Was the Y+ W relay YELLOW
const byte RELAY_XZ_DIR = 5; // DIR 1 X+ X- North / South Was the X- S relay BLUE
const int chipSelect = 4;
const byte UNUSED09 = 9; // cycle timer 26 Hz 38ms period
const byte UNUSED10 = 10;
const byte UNUSED11 = 11;
const byte WATCHDOG = 12;
IPAddress ip(192,168,42,1) ;
IPAddress CurrentIP ;
char ssid[24] = {"North_Tracker\0"}; // your network SSID (name)
char pass[16] = {"password\0" }; // your network password
int status = WL_IDLE_STATUS; // the Wifi radio's status
int reqCount = 0; // number of requests received
static bool hasSD = false;
static bool hasNet = false;
static bool hasGyro = false;
static bool hasRTC = false;
static bool hasPres = false ;
L3G gyro;
LSM303 compass;
LiquidCrystal_I2C lcd(0x27); // Set the LCD I2C address I modified the lib for default wiring
SFE_BMP180 pressure;
HT16K33 HT;
TinyGPS gps;
WiFiEspServer server(80);
RingBuffer buf(8);
Modbus mb_slave(ID, 2, 0); // this is slave ID and RS-232 or USB-FTDI
time_t chiptime ;
uint8_t rtc_status ;
uint8_t time[8];
int motor_recycle_x = 0 ;
int motor_recycle_y = 0 ;
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev_millis;
uint8_t u8state; // machine state
uint8_t u8query; // pointer to message query
char buff[BUFF_MAX];
char trackername[18] ;
unsigned long gpschars ;
float heading ; // MODBUS MAP
struct ts t; //
struct ts td; //
struct ts tg; //
struct ts tc; //
float ha ;
float sunX ;
float sunrise ;
float sunset ;
int iNightShutdown ; //
int iMultiDrive ; // 69 do the axis drives run together
time_t setchiptime ; // 68 if set to non zero this will trigger a time set event
float zAng ; // 66
float xMul = 1.0 ; // 64
float yMul = 1.0 ; // 62
float zMul = 1.0 ; // 60
int iXYS = 0 ; // 59
int iSave = 0 ; // 58
int iDoSave = 0 ; // 57
int iGPSLock = 0 ; // 56
unsigned long fixage ; // 54
float xRoll = 0.0 ; // 52
float yRoll = 0.0 ; // 50
float zRoll = 0.0 ; // 48
float gT ; // 46 temp from sensor
float Pr ; // 44 presure sensor
float alt ; // 42 altitude from GPS
float T; // 40 temperature of board (if has RTC)
float xzTarget ; // 38 target for angles
float yzTarget ; // 36
float xzH ; // 34 hyserisis zone
float yzH ; // 32
float xzAng; // 30 current angles
float yzAng; // 28
float xzOffset; // 26 offset xz
float yzOffset; // 24 offset yz
float dyPark; // 22 parking position
float dxPark; // 20
float xMinVal ; // 18 Min and Max values X - N/S
float xMaxVal ; // 16
float yMinVal ; // 14 Y -- E/W
float yMaxVal ; // 12
float latitude; // 10
float longitude; // 8
int timezone; // 7
int iDayNight ; // 6
float solar_az_deg; // 4
float solar_el_deg; // 2
int iTrackMode ; // 1
int iMode ; // 0
int iPMode;
int iPWM_YZ ;
int iPWM_XZ ;
int iPowerUp = 0 ;
unsigned long tempus;
int8_t state1 = 0;
int8_t rtc_hour = 0;
int8_t rtc_min = 0 ;
int8_t rtc_sec = 0 ;
void LoadParamsFromEEPROM(bool bLoad){
if ( bLoad ) {
xzH = LoadFloatFromEEPROM(0,0.1,20.0,4.0); // hysterisis NS
yzH = LoadFloatFromEEPROM(1,0.1,20.0,4.0); // "" EW
dyPark = LoadFloatFromEEPROM(2,-70.0,50.0,0);
dxPark = LoadFloatFromEEPROM(3,-5.0,50.0,0.0);
xzOffset = LoadFloatFromEEPROM(4,-90.0,90.0,0); // NS
yzOffset = LoadFloatFromEEPROM(5,-90.0,90.0,0); // EW
xzTarget = LoadFloatFromEEPROM(6,-90.0,90.0,0); // NS
yzTarget = LoadFloatFromEEPROM(7,-90.0,90.0,0); // EW
xMinVal = LoadFloatFromEEPROM(8,-10.0,60.0,0.0); // NS
xMaxVal = LoadFloatFromEEPROM(9,-10.0,60.0,45);
yMinVal = LoadFloatFromEEPROM(10,-70.0,50.0,-65); // EW
yMaxVal = LoadFloatFromEEPROM(11,-70.0,50.0,45);
iTrackMode = LoadIntFromEEPROM(12,-1,4,0);
latitude = LoadFloatFromEEPROM(13,-90.0,90.0,-34.051219);
longitude = LoadFloatFromEEPROM(14,-180.0,180.0,142.013618);
timezone = LoadIntFromEEPROM(15,0,23,10);
xMul = LoadFloatFromEEPROM(16,-10,10,1);
yMul = LoadFloatFromEEPROM(17,-10,10,1);
zMul = LoadFloatFromEEPROM(18,-10,10,1);
iXYS = LoadIntFromEEPROM(19,0,1,0);
if ( xMul == 0.0 ) // zero is rubbish value so take 1.0 as the default
xMul = 1.0 ;
if ( yMul == 0.0 )
yMul = 1.0 ;
if ( zMul == 0.0 )
zMul = 1.0 ;
iNightShutdown = LoadIntFromEEPROM(20,0,1,1);
iMultiDrive = LoadIntFromEEPROM(21,0,1,0);
if (digitalRead(FACTORY_RESET)== LOW) {
ip= IPAddress(192,168,42,1);
sprintf(trackername,"Most Excellent\0");
sprintf(ssid , "Configure\0") ;
sprintf(pass, "password\0");
}else{
EEPROM.get(0 + (22 * sizeof(float)) , ip );
if ((( ip[0] == 255 ) && ( ip[1] == 255 ))) {
ip= IPAddress(192,168,42,1);
}
EEPROM.get(0 + (30 * sizeof(float)) , trackername );
if ( String(trackername).length() < 2 ){
sprintf(trackername,"Most Excellent\0");
}
EEPROM.get(0 + (35 * sizeof(float)) , ssid );
if (( String(ssid).length() < 2 ) || ((ssid[0] == ssid[11]) && (ssid[14] == ssid[15]) ) ){
sprintf(ssid , "Configure\0") ;
sprintf(pass, "password\0");
}else{
EEPROM.get(0 + (42 * sizeof(float)) , pass );
}
}
}else{
EEPROM.put( 0 , xzH );
EEPROM.put(0 + (1 * sizeof(float)) , yzH );
EEPROM.put(0 + (2 * sizeof(float)) , dyPark );
EEPROM.put(0 + (3 * sizeof(float)) , dxPark );
EEPROM.put(0 + (4 * sizeof(float)) , xzOffset );
EEPROM.put(0 + (5 * sizeof(float)) , yzOffset );
EEPROM.put(0 + (6 * sizeof(float)) , xzTarget );
EEPROM.put(0 + (7 * sizeof(float)) , yzTarget );
EEPROM.put(0 + (8 * sizeof(float)) , xMinVal );
EEPROM.put(0 + (9 * sizeof(float)) , xMaxVal );
EEPROM.put(0 + (10 * sizeof(float)) , yMinVal );
EEPROM.put(0 + (11 * sizeof(float)) , yMaxVal );
EEPROM.put(0 + (12 * sizeof(float)) , iTrackMode );
EEPROM.put(0 + (13 * sizeof(float)) , latitude );
EEPROM.put(0 + (14 * sizeof(float)) , longitude );
EEPROM.put(0 + (15 * sizeof(float)) , timezone );
EEPROM.put(0 + (16 * sizeof(float)) , xMul );
EEPROM.put(0 + (17 * sizeof(float)) , yMul );
EEPROM.put(0 + (18 * sizeof(float)) , zMul );
EEPROM.put(0 + (19 * sizeof(float)) , iXYS );
EEPROM.put(0 + (20 * sizeof(float)) , iNightShutdown );
EEPROM.put(0 + (21 * sizeof(float)) , iMultiDrive );
EEPROM.put(0 + (22 * sizeof(float)) , ip );
EEPROM.put(0 + (30 * sizeof(float)) , trackername);
EEPROM.put(0 + (35 * sizeof(float)) , ssid);
EEPROM.put(0 + (42 * sizeof(float)) , pass);
}
}
void setup() {
int led ;
Wire.begin();
lcd.begin(20, 4);
lcd.home();
lcd.setBacklightPin(3, NEGATIVE);
lcd.noCursor();
lcd.clear();
MCUSR &= ~_BV(WDRF);
wdt_disable();
compass.init();
compass.enableDefault();
compass.setTimeout(1000);
Serial.begin(115200); // program/debug port
Serial1.begin(9600); // GPS port
// Serial2.begin(9600); // Modbus Port
Serial3.begin(115200); // EPS8266 serial converter
if (gyro.init()) {
gyro.enableDefault();
hasGyro = true ;
}
if (pressure.begin()){
Serial.println("BMP180 init success");
hasPres = true ;
}
pinMode(FACTORY_RESET,INPUT_PULLUP);
pinMode(RELAY_XZ_DIR, OUTPUT); // Outputs for PWM motor control
pinMode(RELAY_XZ_PWM, OUTPUT); //
pinMode(RELAY_YZ_PWM, OUTPUT); //
pinMode(RELAY_YZ_DIR, OUTPUT); //
iPWM_YZ = 0 ;
iPWM_XZ = 0 ;
pinMode(13, OUTPUT); //
digitalWrite(13, HIGH );
ActivateRelays(0); // call an all stop first
mb_slave.begin( 9600 ); // RS-232 to base of tower
tempus = millis() + 100;
pinMode(UNUSED09, OUTPUT); // unused so dont leave floating set as output
pinMode(UNUSED10, OUTPUT); //
pinMode(UNUSED11, OUTPUT); //
pinMode(WATCHDOG, OUTPUT); //
digitalWrite(WATCHDOG,HIGH);
compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical
compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300};
LoadParamsFromEEPROM(true);
DS3231_init(DS3231_INTCN); // look for a rtc
DS3231_get(&tc);
DS3231_get(&td);
rtc_status = DS3231_get_sreg();
if ((tc.mon == 0 )&& (tc.mday==0)){ // no rtc to load off
setTime (0,0,0,21,9,2017) ; // midnight on the equinox (will deactivae motors till gets a valid time) ;
}else{
setTime((int)tc.hour,(int)tc.min,(int)tc.sec,(int)tc.mday,(int)tc.mon,(int)tc.year ) ; // set the internal RTC
hasRTC = true ;
}
HT.begin(0x00);
for (led = 0; led < 127; led++) {
HT.clearLedNow(led);
}
Serial3.begin(115200); // initialize serial for ESP module
WiFi.init(&Serial3); // initialize ESP module
// check for the presence of the shield
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// while (true); // don't continue
}
Serial.print("Attempting to start AP ");
Serial.println(ssid);
if (( ip[0] == 0 )&&( ip[1] == 0 )&&( ip[2] == 0 )&&( ip[3] == 0 ) && (digitalRead(FACTORY_RESET)== HIGH)){
WiFi.begin((char*)ssid, (char*)pass) ;
}else{
WiFi.configAP(ip); // start access point
if ( String(pass).length() == 0 ) {
status = WiFi.beginAP(ssid, 10);
}else{
status = WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
}
}
Serial.println("Access point started");
// printWifiStatus();
Serial.println("IP address: ");
CurrentIP = WiFi.localIP() ;
Serial.println(CurrentIP);
// start the web server on port 80
server.begin();
Serial.println("Server started");
// wdt_enable(WDTO_8S);
}
// Arduino doesnt have these to we define from a sandard libruary
float arcsin(float x) {
return (atan(x / sqrt(-x * x + 1)));
}
float arccos(float x) {
return (atan(x / sqrt(-x * x + 1)) + (2 * atan(1)));
}
// fractional orbital rotation in radians
float gama(struct ts *tm) {
return ((2 * PI / 365 ) * DayOfYear(tm->year , tm->mon , tm->mday , tm->hour , tm->min ));
}
// equation of rime
float eqTime(float g) {
return (229.18 * ( 0.000075 + ( 0.001868 * cos(g)) - (0.032077 * sin(g)) - (0.014615 * cos (2 * g)) - (0.040849 * sin(2 * g))));
}
// declination of sun in radians
float Decl(float g) {
return ( 0.006918 - (0.399912 * cos(g)) + (0.070257 * sin(g)) - (0.006758 * cos(2 * g)) + ( 0.000907 * sin(2 * g)) - ( 0.002697 * cos(3 * g)) + (0.00148 * sin(3 * g)) );
}
float TimeOffset(float longitude , struct ts *tm , int timezone ) {
float dTmp ;
dTmp = (-4.0 * longitude ) + (60 * timezone) - eqTime(gama(tm)) ;
return (dTmp);
}
float TrueSolarTime(float longitude , struct ts *tm , int timezone ) {
float dTmp ;
dTmp = ( 60.0 * tm->hour ) + (1.0 * tm->min) + (1.0 * tm->sec / 60) - TimeOffset(longitude, tm, timezone) ;
return (dTmp);
}
float HourAngle(float longitude , struct ts *tm , int timezone) {
float dTmp;
dTmp = (TrueSolarTime(longitude, tm, timezone) / 4 ) - 180 ; // 720 minutes is solar noon -- div 4 is 180
return (dTmp);
}
// Hour angle for sunrise and sunset only
float HA (float lat , struct ts *tm ) {
float latRad ;
latRad = lat * 2 * PI / 360 ;
return ( acos((cos(90.833 * PI / 180 ) / ( cos(latRad) * cos(Decl(gama(tm)))) - (tan(latRad) * tan(Decl(gama(tm)))))) / PI * 180 );
}
float Sunrise(float longitude , float lat , struct ts *tm , int timezone) {
return (720 - ( 4.0 * (longitude + HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ;
}
float Sunset(float longitude , float lat , struct ts *tm , int timezone) {
return (720 - ( 4.0 * (longitude - HA(lat, tm))) + (60 * timezone) - eqTime(gama(tm)) ) ;
}
float SNoon(float longitude , float lat , struct ts *tm , int timezone) {
return (720 - ( 4.0 * (longitude + (60 * timezone) - eqTime(gama(tm)))) ) ;
}
float SolarZenithRad(float longitude , float lat , struct ts *tm , int timezone) {
float latRad ;
float decRad ;
float HourAngleRad ;
float dTmp ;
latRad = lat * 2 * PI / 360 ;
decRad = Decl(gama(tm));
HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ;
dTmp = acos((sin(latRad) * sin(decRad)) + (cos(latRad) * cos(decRad) * cos(HourAngleRad)));
return (dTmp) ;
}
float SolarElevationRad(float longitude , float lat , struct ts *tm , int timezone ) {
return ((PI / 2) - SolarZenithRad(longitude , lat , tm , timezone )) ;
}
float SolarAzimouthRad(float longitude , float lat , struct ts *tm , int timezone) {
float latRad ;
float decRad ;
float solarzenRad ;
float HourAngleRad ;
float dTmp ;
latRad = lat * 2 * PI / 360 ;
decRad = Decl(gama(tm));
solarzenRad = SolarZenithRad ( longitude , lat , tm , timezone ) ;
HourAngleRad = HourAngle (longitude , tm , timezone ) * PI / 180 ;
dTmp = acos(((sin(decRad) * cos(latRad)) - (cos(HourAngleRad) * cos(decRad) * sin(latRad))) / sin(solarzenRad)) ;
if ( HourAngleRad < 0 ) {
return (dTmp) ;
} else {
return ((2 * PI) - dTmp) ;
}
}
void StopYZ(){
iPWM_YZ=0 ;
motor_recycle_y = MOTOR_DWELL ;
}
void StopXZ(){
iPWM_XZ=0 ;
motor_recycle_x = MOTOR_DWELL ;
}
void ActivateRelays(int iAllStop) {
if (motor_recycle_y > 0 ){
motor_recycle_y-- ;
}
if (motor_recycle_x > 0 ){
motor_recycle_x-- ;
}
if ( iAllStop == 0 ) {
StopYZ() ;
StopXZ() ;
} else {
if (( iPWM_YZ==0 ) && (motor_recycle_y == 0 )){
if ((( yzAng ) < ( yzTarget - yzH )) ) { // do Y ie E/W before N/S
digitalWrite(RELAY_YZ_DIR, LOW) ;
iPWM_YZ=2 ;
}
if ((( yzAng ) > ( yzTarget + yzH )) ) {
digitalWrite(RELAY_YZ_DIR, HIGH) ;
iPWM_YZ=2 ;
}
}
if ( iPWM_YZ>0 ){
if ((yzAng > yzTarget) && ( digitalRead(RELAY_YZ_DIR)==LOW )) {
StopYZ() ;
}
if ((yzAng < yzTarget) && ( digitalRead(RELAY_YZ_DIR)==HIGH )) {
StopYZ() ;
}
}
if (( iPWM_YZ==0) || ( iMultiDrive == 1 )) { // if finished on E/W you can do N/S or if we are doing multidrive
if (( iPWM_XZ==0 ) && (motor_recycle_x == 0 )){
if ((xzAng < ( xzTarget - xzH )) ) { // turn on if not in tolerance
digitalWrite(RELAY_XZ_DIR, LOW) ;
iPWM_XZ=2 ;
}
if ((xzAng > ( xzTarget + xzH )) ) { // turn on if not in tolerance
digitalWrite(RELAY_XZ_DIR, HIGH) ;
iPWM_XZ=2 ;
}
}
}else{
if ((iPWM_XZ>0 )){
StopXZ() ;
}
}
if ( iPWM_XZ>0 ){
if ((xzAng > xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==LOW )) { // if on turn off
StopXZ() ;
}
if ((xzAng < xzTarget ) && ( digitalRead(RELAY_XZ_DIR)==HIGH )) { // if on turn off
StopXZ() ;
}
}
}
if (iPWM_XZ>0){
iPWM_XZ += 2 ;
}
if (iPWM_YZ>0){
iPWM_YZ += 2 ;
}
iPWM_XZ = constrain(iPWM_XZ,0,254);
iPWM_YZ = constrain(iPWM_YZ,0,254);
analogWrite(RELAY_XZ_PWM,iPWM_XZ);
analogWrite(RELAY_YZ_PWM,iPWM_YZ);
}
void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) {
uint16_t tempdata[2] ;
float *tf ;
tf = (float * )&tempdata[0] ;
*tf = src_value ;
*dest_lo = tempdata[1] ;
*dest_hi = tempdata[0] ;
}
float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) {
uint16_t tempdata[2] ;
float *tf ;
tf = (float * )&tempdata[0] ;
tempdata[1] = dest_lo ;
tempdata[0] = dest_hi ;
return (*tf) ;
}
float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){
float tmp ;
EEPROM.get(0 + (address * sizeof(float)) , tmp );
if (( tmp < minval ) || ( tmp > maxval )|| (NumberOK(tmp) == 1)) {
tmp = defaultval ;
EEPROM.put(0 + (address * sizeof(float)) , tmp );
}
return(tmp);
}
int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){
int tmp ;
EEPROM.get(0 + (address * sizeof(float)) , tmp ); // float.. yeah yeah I know... but it makes it compatible with the one above (easy on the brain)
if (( tmp < minval ) || ( tmp > maxval )) {
tmp = defaultval ;
EEPROM.put(0 + (address * sizeof(float)) , tmp );
}
return(tmp);
}
int NumberOK (float target) {
int tmp = 0 ;
tmp = isnan(target);
if ( tmp != 1 ) {
tmp = isinf(target);
}
return (tmp);
}
int SetTimeFromGPS(){
byte hundredths ;
tmElements_t tmegps;
gps.crack_datetime((int *)&tg.year,(byte *)&tg.mon,(byte *) &tg.mday,(byte *) &tg.hour,(byte *) &tg.min,(byte *) &tg.sec , &hundredths, &fixage);
tmegps.Year = tg.year - 1970 ;
tmegps.Month = tg.mon ;
tmegps.Day = tg.mday ;
tmegps.Hour = tg.hour ;
tmegps.Minute = tg.min ;
tmegps.Second = tg.sec ;
// setTime((int)tg.hour,(int)tg.min,(int)tg.sec,(int)tg.mday,(int)tg.mon,(int)tg.year ) ; // set the internal RTC from last GPS time
// chiptime = now() ; // get it back again
chiptime = makeTime(tmegps); // get the GPS as time_t
chiptime += (( timezone * SECS_PER_HOUR ) + ( fixage / 1000 )) ; // add the offset plus the fix age
setTime(chiptime); // set it again
if (hasRTC) {
tg.year = year();
tg.mon = month() ;
tg.mday = day();
tg.hour = hour() ;
tg.min = minute();
tg.sec = second();
DS3231_set(tg); //should also update this
}
return(0);
}
void loop() {
float P;
float sunInc;
float sunAng;
float xzRatio;
float yzRatio;
float decl ;
float eqtime ;
float dTmp ;
float heading ;
float tst ;
float flat, flon;
unsigned short goodsent;
unsigned short failcs;
String request ;
// int iYear , iMon , iMday , iHour , iMin , iSec ;
if (minute() != rtc_min) { // do onlyonce a minute
gps.stats(&gpschars, &goodsent , &failcs );
gps.f_get_position(&flat, &flon,(long unsigned *) &fixage); // return in degrees
if (hasPres){
Pr = getPressure((double *)&gT) ;
}
if (hasRTC) {
T = DS3231_get_treg();
}
rtc_min = minute() ;
if ((fixage > 0 ) && ( fixage < 40000 )) { // wait till our fix is valid before we use the values
latitude = flat ;
longitude = flon ;
iGPSLock = gps.satellites() ;
alt = gps.f_altitude() ;
if (iPowerUp==0) { // only do this at startup so we have a better position ref for next time
EEPROM.put(0 + (13 * sizeof(float)) , latitude );
EEPROM.put(0 + (14 * sizeof(float)) , longitude );
iPowerUp = 1 ;
if (!hasNet ){
SetTimeFromGPS();
}
}
}else{
iGPSLock = 0 ; // if no lock loook at internal clock
}
}
tc.year = year();
tc.mon = month() ;
tc.mday = day();
tc.hour = hour() ;
tc.min = minute();
tc.sec = second();
compass.read(); // this reads all 6 channels
if ( hasGyro ){
gyro.read();
xRoll = gyro.g.x ;
yRoll = gyro.g.y ;
zRoll = gyro.g.z ;
}
digitalWrite(UNUSED09,!digitalRead(UNUSED09)); // toggle this output so I can measure the cycle time with a scope
heading = compass.heading((LSM303::vector<int>) { 1, 0, 0 });
if (( compass.a.z != 0) && (!compass.timeoutOccurred() )) {
zAng = (float)compass.a.z ;
if (iXYS == 0 ){ // Proper Job make it configurable
xzRatio = (float)compass.a.x * xMul / abs(zAng) ; // Normal
yzRatio = (float)compass.a.y * yMul / abs(zAng) ;
}else{
xzRatio = (float)compass.a.y * xMul / abs(zAng) ; // Swapped
yzRatio = (float)compass.a.x * yMul / abs(zAng) ;
}
xzAng = ((float)atan(xzRatio) / PI * 180 ) + xzOffset ; // good old offsets or fudge factors
yzAng = ((float)atan(yzRatio) / PI * 180 ) + yzOffset ;
// digitalWrite(13, LOW);
}else{ // try restarting the compass/accelerometer modual - cos he gone walkabout...
Wire.begin(); // reset the I2C
compass.init();
compass.enableDefault();
compass.setTimeout(1000); // BTW I fixed up the int / long issue in the time out function in the LM303 lib I was using
compass.m_min = (LSM303::vector<int16_t>) {-3848, -1822, -1551 }; // calibration figures are empirical (just whirl it around a bit and records the min max !!)
compass.m_max = (LSM303::vector<int16_t>) { +3353, +5127, +5300 };
/* if (tc.sec % 2 == 0 ) {
digitalWrite(13, HIGH);
} else {
digitalWrite(13, LOW);
}*/
HT.begin(0x00);
}
if (setchiptime > 0) { // update the arduino time from the modbus register then clear it... also set RTC if fitted
setTime(setchiptime) ;
if (hasRTC) {
tc.year = year();
tc.mon = month() ;
tc.mday = day();
tc.hour = hour() ;
tc.min = minute();
tc.sec = second();
DS3231_set(tc); //should also update this
}
setchiptime = 0 ;
}
if ( hour() != rtc_hour){ // update our time every hour if we can
if (iGPSLock == 0){
if (hasRTC) {
DS3231_get(&td);
setTime((int)td.hour,(int)td.min,(int)td.sec,(int)td.mday,(int)td.mon,(int)td.year ) ; // set the internal RTC from Dallas RTC
}
}else{
if ((fixage > 0 ) && ( fixage < 10000 )) { // if the lock is less than 10 second old
SetTimeFromGPS();
}
}
rtc_hour = hour() ;
}
if ( rtc_sec != second() ) { //only update once a second
wdt_reset(); // reset internal watchdog - good puppy
if (( tc.sec > 8 ) && ( tc.sec < 58 )) { // dont calculate arround the minute when time is updating from NTP or GPS as might get a not so funny result
digitalWrite(13,!digitalRead(13));
solar_az_deg = SolarAzimouthRad(longitude, latitude, &tc, timezone) * 180 / PI ;
solar_el_deg = SolarElevationRad(longitude, latitude, &tc, timezone) * 180 / PI ;
decl = Decl(gama(&tc)) * 180 / PI ;
ha = HourAngle (longitude , &tc , timezone ) ;
sunrise = Sunrise(longitude, latitude, &tc, timezone) ;
sunset = Sunset(longitude, latitude, &tc, timezone);
tst = TrueSolarTime(longitude, &tc, timezone);
sunX = abs(latitude) + decl ;
if (solar_el_deg >= 0 ){ // day
iDayNight = 1 ;
}else{ // night
iDayNight = 0 ;
}
}
switch (iTrackMode) {
case 4: // both axis to park
yzTarget = dyPark ; // night park position E/W
xzTarget = dxPark ; // night park position N/S
break ;
case 3: // both axis off no tracking
break ;
case 2: // xz tracking NS
if ( iDayNight == 1 ) {
xzTarget = sunX ; // need to map the coordinate system correctly
} else {
xzTarget = dxPark ; // night park position
}
break;
case 1: // yz tracking EW
if (iDayNight == 1) {
yzTarget = ha ;
} else {
yzTarget = dyPark ; // night park position
}
break;
case -1: // set target to tracking and park both at nigh
if (iDayNight == 1) {
yzTarget = ha ;
xzTarget = sunX ; // need to map the coordinate system correctly
} else {
yzTarget = dyPark ; // night park position E/W
xzTarget = dxPark ; // night park position N/S
}
break;
default: // set target to tracking
if (iDayNight == 1) {
yzTarget = ha ;
xzTarget = sunX ; // need to map the coordinate system correctly
} else {
yzTarget = dyPark ; // night park position (dont park the other - leave till morning)
}
break;
}
xzTarget = constrain(xzTarget,xMinVal,xMaxVal); // constain function... very cool - dont leave home without it !
yzTarget = constrain(yzTarget,yMinVal,yMaxVal);
lcd.setCursor ( 0, 0 ); // Diags in case there is an LCD display attached
lcd.print("X/Z ");
if ( xzAng > 0 ) {
lcd.print("+");
}
lcd.print(xzAng);
lcd.setCursor ( 10, 0 );
lcd.print("Y/Z ");
if ( yzAng > 0 ) {
lcd.print("+");
}
lcd.print(yzAng);
lcd.setCursor ( 0, 1 );
lcd.print("TX ");
if (( xzTarget) > 0 ) {
lcd.print("+");
}
lcd.print(( xzTarget));
lcd.setCursor ( 10, 1 );
lcd.print("TY ");
if (( yzTarget) > 0 ) {
lcd.print("+");
}
lcd.print(( yzTarget));
lcd.setCursor ( 0, 2 );
lcd.print("DX ");
dTmp = ( xzAng - xzTarget) ;
if (dTmp > 0 ) {
lcd.print("+");
}
lcd.print(dTmp);
lcd.setCursor ( 10, 2 );
lcd.print("DY ");
dTmp = ( yzAng - yzTarget) ;
if (dTmp > 0 ) {
lcd.print("+");
}
lcd.print(dTmp);
lcd.setCursor ( 0, 3 ); // line 3
snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", tc.hour, tc.min, tc.sec);
lcd.print(buff) ;
lcd.setCursor ( 9, 3 ); // line 3
lcd.print( "S") ;
if ( iDayNight == 0 ) {
lcd.print( "-") ;
}else{
if (( tc.sec % 2 ) == 0 ) {
lcd.print( "<") ;
}else{
lcd.print( ">") ;
}
}
if ( gps.satellites() > 9 ){
lcd.print( "-" );
}else{
lcd.print(gps.satellites()) ;
}
lcd.setCursor ( 13, 3 ); // line 3
snprintf(buff, BUFF_MAX, "%04X", fixage);
lcd.print(buff) ;
lcd.setCursor ( 18, 3 ); // line 3
if ( iPWM_YZ == 0 ) {
lcd.print( " ") ;
}else{
if (( digitalRead(RELAY_YZ_DIR) == LOW )) {
lcd.print( "W") ;
}else{
lcd.print( "E") ;
}
}
lcd.setCursor ( 19, 3 ); // line 3
if ( iPWM_XZ == 0 ) {
lcd.print( " ") ;
}else{
if (( digitalRead(RELAY_XZ_DIR) == LOW )) {
lcd.print( "N") ;
}else{
lcd.print( "S") ;
}
}
rtc_sec = second() ;
DisplayMeatBall() ;
}
if ( iDoSave == 2 ) { // save them Active via web or
LoadParamsFromEEPROM(false);
iDoSave = 0 ; // only do once
}
if ( iDoSave == 3 ) { // load them
LoadParamsFromEEPROM(true);
iDoSave = 0 ; // only do once
}
if (((tc.hour > 19 ) || ( tc.hour < 5 )) && (iTrackMode < 3)) {
if ( iNightShutdown != 0 ){
ActivateRelays(1) ;
}else{
ActivateRelays(0) ; // power down at night if in tracking mode
}
}else{
ActivateRelays(1) ;
}
state1 = mb_slave.poll( (uint16_t*)&iMode, MAX_MODBUS_DATA );
switch (state1) {
case EXC_ADDR_RANGE:
Serial.println("EXC_ADDR_RANGE PORT 2");
break;
case EXC_FUNC_CODE:
Serial.println("EXC_FUNC_CODE PORT 2");
break;
case EXC_REGS_QUANT:
Serial.println("EXC_REGS_QUANT PORT 2");
break;
}
while (Serial1.available()){ // process the gps buffer
gps.encode(Serial1.read());
}
WiFiEspClient client = server.available(); // listen for incoming clients
if (client) { // if you get a client,
ActivateRelays(0); // deactive motor while we do web
Serial.println("New client"); // print a message out the serial port
buf.init(); // initialize the circular buffer
request = "" ;
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
buf.push(c); // push it to the ring buffer
request += c ;
// you got two newline characters in a row
// that's the end of the HTTP request, so send a response
if (buf.endsWith("\r\n\r\n")) {
// if (request.endsWith("\r\n\r\n")){
// Serial.print(request);
processRequest(request);
if (request.indexOf("favicon.ico")>0){
sendHttpResponseNG(client);
}else{
sendHttpResponse(client);
}
/* Serial.println(request.endsWith("\r\n\r\n"));
Serial.println(request.indexOf("\r\n\r\n")); */
client.flush();
break;
}
}
}
// give the web browser time to receive the data
delay(10);
//close the connection
client.stop();
Serial.println("Client disconnected");
}
} // end of loop
float DayOfYear(uint16_t iYear , uint8_t iMon , uint8_t iDay , uint8_t iHour , uint8_t iMin ) {
int i ;
float iTDay ;
iTDay = iDay - 1 ; // this is zero referenced
for ( i = 1 ; i < iMon ; i++ ) {
switch (i) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
iTDay += 31 ;
break;
case 4:
case 6:
case 9:
case 11:
iTDay += 30 ;
break;
case 2 :
if ((iYear % 4) == 0 ) {
iTDay += 29 ;
} else {
iTDay += 28 ;
}
break;
}
}
iTDay += (( 1.0 * iHour - 12 ) / 24 ) ;
// iDay += 1.0 * iMin / 1440 ;
return (iTDay);
}
int HrsSolarTime(float target) {
int i ;
i = target ;
return ( i / 60 );
}
int MinSolarTime(float target) {
int i ;
i = target ;
return ( i % 60 );
}
float sign(float target) {
if (target > 0 ) {
return (1);
} else {
if (target < 0 ) {
...
This file has been truncated, please download it to see its full contents.
Comments