/*-----------------------------------------------------------------------------------------
* This software is in the public domain, furnished "as is", without technical
* support, and with no warranty, express or implied, as to its usefulness for
* any purpose.
*
* FlashLED.ino
*
* Function to time 4 high power LEDs during rotation of the ship.
* The LEDs are 60 degrees separeted from each other alonge the round body of the ship.
* The 0 and 6 o'clock spaces are reserved for Loudspeaker and Fog-function.
* The modes are triggered with the two switches of Switchprop switchOn[S0,S1] and
* combinated with the turntable modes.
* PropMode [0,0]: FlashLEDs run against turntable with same rotation speed -> PropFlashLED
* Single FlashLED will flash as long turntable is in that sector (1/12 of full rotation interval)
* ServoMode[0,1]: FlashLEDs runs clock or anticlock wise matching turntable deflection. Flash cycle get faster as
* delta position of turntable front to centerposition rises -> ServoFlashLED
* RotMode [1,0]: FlashLEDs are triggered if turntable front is in line with it.
* The Flash Duration is shorter with higher turntable rotation speeds.
* If ship is not rotating no LED will be flashed -> SyncFlashLED
* SyncMode [1,1]: FlashLEDs are triggered if turntable front is in line with it.
* The Flash Duration is shorter with higher turntable rotation speeds.
* If ship is not rotating no LED will be flashed -> SyncFlashLED
* Function calls of FlashLED are consolidated within Turntable.ino runTable() function.
*
* Author: Volker Frauenstein
* Date: 13/01/2023 Version: 1.2 implementation of functions for SyncFlashLED and ServoFlashLED
*
* Date: 09/01/2023 Version: 1.1 implementation of interface to Mosfett swiches and function PropFlashLED
* Date: 04/12/2022 Version: 1.0 implementation of interface to retais card
*
*/
// pinout definition for the relais to trigger the 4 Flash LEDs
const int Flash1 = 32; // control pin for Flash LED on 2 o'clock
const int Flash2 = 33; // control pin for Flash LED on 4 o'clock
const int Flash4 = 25; // control pin for Flash LED on 8 o'clock
const int Flash5 = 27; // control pin for Flash LED on 10 o'clock
// generig definitions for debug
//#define DEBUG_F 1 // set activ if debuging of Flash function is needed
// definitions for adjustable values
int FlashDurFactor = 2; // factor for flash duration in times of 20ms (e.g 3 -> flash min 60ms / max 240ms )
const float dzServo = 0.1; // Deadzone of x% positiv values of ServoFlashLED function
const float dzNServo = - 0.1; // RC Channel Deadzone of x% negativ values of ServoFlashLED function
// generig definitions
const int FlashNum = 5; // number of FlashLEDs excluding position 12 o'clock
const int FlashPosMid[FlashNum] = {33, 67, 100, 133, 167}; // Position of FlashLEDs as stepposition of Turntable
const int FlashPosStart[FlashNum] = {17, 51, 84, 116, 151}; // Position of FlashLEDs area start as stepposition of Turntable
const int FlashPosEnd[FlashNum] = {50, 83, 115, 150, 183}; // Position of FlashLEDs area end as stepposition of Turntable
const int FlashPos[FlashNum] = {4, 3, 2, 1, 0}; // array to replace rotating position for PropFlashLED funktion
bool FlashOn[FlashNum] = {false,false,false,false,false}; // flag to mark if single LED is on
uint8_t FlashRunning = 0; // counter for running flashes in 20ms intervals
int VOffset = 0; // virtuel stepOffset
void setup_FlashLED() { // set up function to attach the relais / LEDs to I/O pin
pinMode(Flash1, OUTPUT);
pinMode(Flash2, OUTPUT);
pinMode(Flash4, OUTPUT);
pinMode(Flash5, OUTPUT);
failsafe_FlashLED(); // and switch off all relais / LEDs
}
void failsafe_FlashLED() { // set all relais / LEDs to to failsafe state
digitalWrite(Flash1, LOW);
digitalWrite(Flash2, LOW);
digitalWrite(Flash4, LOW);
digitalWrite(Flash5, LOW);
}
// main functions for modes of the 4 FlashLEDs
void PropFlashLED(int Steps) { // function to coordinate FlashLED switching oposite of turntable position
int TempPos = stepOffset + (Steps/2); // turntable position at midterm of this PWM cycle
uint8_t i; // counter for loop
bool Sector0 = true; // flag to mark sector with stepcounter overrun
if (TempPos < 0) { // turtable will cross startposition
TempPos = TempPos + 200;
} // no else needed
#ifdef DEBUG_F
int j;
Serial.print("TempPos: ");Serial.print(TempPos);Serial.print(", ");
#endif
for (i = 0; i < FlashNum; i++) { // run over the FlasLED position and check if we are inside
// i=0 is turntable on FlashLED position 2 o'clock
if (constrain(TempPos, FlashPosStart[i], FlashPosEnd[i])== TempPos) {
Sector0 = false; // sector found other than 12 o'clock
if (FlashOn[FlashPos[i]]) { // check if still in same sector and FlashLED is already on
#ifdef DEBUG_F
Serial.print("FlashOn[");Serial.print(FlashPos[i]);Serial.print("] on, ");
#endif
return;
}
else { // turntable has reached next FlashLED area
switch (i) { // switch of last FlashLED and switch on new one
case 0: // turntable is on 2 o'clock position,
digitalWrite(Flash4, LOW ); // if turntable goes anticlockwise we should
FlashOn[FlashPos[i+1]] = false;// swicht of FlashLED on 8 o'clock and set flag
digitalWrite(Flash5, HIGH); // switch on FlashLED on 10 o'clock position
FlashOn[FlashPos[i]] = true; // and set flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("F5on (F4off), ");
#endif
break;
case 1: // turntable is on 4 o'clock position,
digitalWrite(Flash5, LOW); // if turntable goes clockwise we should
FlashOn[FlashPos[i-1]] = false;// swicht of FlashLED on 10 o'clock and set flag
digitalWrite(Flash4, HIGH); // switch on FlashLED on 8 o'clock position
FlashOn[FlashPos[i]] = true; // and set flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("F4on (F5off), ");
#endif
break;
case 2: // turntable is on 6 o'clock position,
digitalWrite(Flash2, LOW); // switch off FlashLED on 4 o'clock position
FlashOn[FlashPos[i+1]] = false;// for anticlockwise turntable rotation and set flag
digitalWrite(Flash4, LOW); // switch off FlashLED on 8 o'clock position
FlashOn[FlashPos[i-1]] = false;// for clockwise turntable rotation andset flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("(F2+F4off), ");
#endif
break; // no FlashLED on 6 o'clock position
case 3: // turntable is on 8 o'clock position,
digitalWrite(Flash1, LOW); // switch on FlashLED on 2 o'clock position
FlashOn[FlashPos[i+1]] = false;// for anticlockwise turntable rotation and set flag
digitalWrite(Flash2, HIGH); // switch on FlashLED on 4 o'clock position
FlashOn[FlashPos[i]] = true; // set flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("F2on (F1off), ");
#endif
break;
case 4: // turntable is on 10 o'clock position,
digitalWrite(Flash2, LOW); // switch off FlashLED on 4 o'clock position
FlashOn[FlashPos[i-1]] = false;// for clockwise turntable rotation and set flag
digitalWrite(Flash1, HIGH); // switch on FlashLED on 2 o'clock position
FlashOn[FlashPos[i]] = true; // set flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("F1on (F2off), ");
#endif
break;
} // end switch case
} // end else alway returned via break
}
} // end for loop
// turntable is on 12 o'clock position,
if (Sector0) { // no FlashLED on 12 o'clock position
digitalWrite(Flash1, LOW); // switch off FlashLED on 2 o'clock position
FlashOn[FlashPos[4]] = false; // for anticlockwise turntable rotation and set flag
digitalWrite(Flash5, LOW); // switch off FlashLED on 10 o'clock position
FlashOn[FlashPos[0]] = false; // for clockwise turntable rotation and set flag
#ifdef DEBUG_F
Serial.print("FlashPos[");Serial.print(FlashPos[i]);Serial.print("], ");
Serial.print("FlashOn[");Serial.print(FlashOn[0]);
for (j = 1;j < FlashNum; j++) {
Serial.print(", ");Serial.print(FlashOn[j]);
}
Serial.print("], ");
Serial.println("(F1+F5off), ");
#endif
}
} // function PropFlashLED closed
void ServoFlashLED(float PosServo){ // function to coordinate FlashLEDs with turntable position in servo mode
if ((PosServo > dzNServo) && (PosServo < dzServo)) {
return; // check if Turntable in deadzone and nop
}
int Vs = PosServo*10; // set value for flash cycle duration as virtual deltasteps
if (!CheckFlashTime()) { // check if one Flash is on
// no,
RunFlashTime(VOffset + (Vs/2), Vs); // prepare checks and switch FlashLEDs
} // if CheckFlashTime end, no else needed for FlashRunning update
VOffset = VOffset + Vs;
if (VOffset < 0) VOffset = VOffset + 200;
if (VOffset > 199) VOffset = VOffset - 200;
//SyncFlashLED(Vsteps);
#ifdef DEBUG_F
Serial.print("nop, FlashServo :");Serial.println(FlashRunning);
#endif
} // function ServoFlashLED closed
void SyncFlashLED(int dS){ // function to coordinate FlashLEDs with turntable position in Rot and Sync mode
if (LED_Mmode == 0 || LED_Mmode == 2) { // do nothing if we are in Moless or LinOnly mode within
#ifdef DEBUG_F
Serial.print("nop Mmode, ");
#endif
return; // return without FlashLED use
}
if (!CheckFlashTime()) { // check if one Flash is on
// no,
RunFlashTime(stepOffset + (dS/2), dS); // prepare checks and switch FlashLEDs
} // if CheckFlashTime end, no else needed for FlashRunning update
#ifdef DEBUG_F
Serial.print("nop, FlashSync :");Serial.println(FlashRunning);
#endif
} // function SyncFlashLED closed
bool CheckFlashTime() { // function to check if flash is
uint8_t i; // counter for loop
if (FlashRunning > 0) { // check if one flash is aready flashing
if (FlashRunning > 1) { // check if Flash must be shut off this cycle
FlashRunning--; // no - just count down
return true;
}
else {
for (i = 0; i < FlashNum; i++) { // yes find Flash to shutoff
if (FlashOn[i]) {
switch (i) { // switch of activ FlashLED
case 0:
digitalWrite(Flash1, LOW); // switch off FlashLED on 2 o'clock position
FlashOn[i] = false; // and switch off flag as well
break;
case 1:
digitalWrite(Flash2, LOW); // switch off FlashLED on 4 o'clock position
FlashOn[i] = false; // and switch off flag as well
break;
case 2:
#ifdef DEBUG_F
Serial.println("Error: CheckFlashTime case 2 should not happen!");
Serial.print("FlashRunning: ");Serial.print(FlashRunning);
Serial.print(", i:");Serial.println(i);
#endif
break;
case 3:
digitalWrite(Flash4, LOW); // switch off FlashLED on 8 o'clock position
FlashOn[i] = false; // and switch off flag as well
break;
case 4:
digitalWrite(Flash5, LOW); // switch off FlashLED on 10 o'clock position
FlashOn[i] = false; // and switch off flag as well
break;
} // switch case end
}
}
FlashRunning = 0; // Flash is off, Timer to zero
return false; // Return
} // Else of FlashRunning > 1 End
} // if FlashRunning > 0 End
else return false; // No Flash was on , just Return
} // function CheckFlashTime closed
void RunFlashTime(int MidPos, int DeltaS) {
if (MidPos > 199) { // turntable will cross startposition clock wise
MidPos = MidPos - 200; // reset SteppCounter
} // no else needed
if (MidPos < 0) { // turnable will cross startposition anti clock wise
MidPos = MidPos + 200; // reset SteppCounter
}
int z = 1 + abs(DeltaS)/2; // calculate boundary of position (higher stepspeed -> larger boundary)
uint8_t i;
for (i = 0; i < FlashNum; i++) { // run over the FlasLED positions and check if turntable is on this position
if (constrain(MidPos, FlashPosMid[i]-z, FlashPosMid[i]+z)== MidPos) {
switch (i) { // found match for position
case 0:
digitalWrite(Flash1, HIGH); // switch on FlashLED on 2 o'clock position,
FlashOn[i] = true; // set flag and flash duration according to actuel stepspeedand
FlashRunning = CalcFlashDuration(z);
#ifdef DEBUG_F
Serial.print("Flash");Serial.print(i+1);Serial.print(" on, Duration:");
Serial.println(FlashRunning);
#endif
break;
case 1:
digitalWrite(Flash2, HIGH); // switch on FlashLED on 4 o'clock position,
FlashOn[i] = true; // set flag and flash duration according to actuel stepspeedand
FlashRunning = CalcFlashDuration(z);
#ifdef DEBUG_F
Serial.print("Flash");Serial.print(i+1);Serial.print(" on, Duration:");
Serial.println(FlashRunning);
#endif
break;
case 2: // no FlashLED on 6 o'clock position
// digitalWrite(Flash3, HIGH);
// FlashOn[i] = true;
// FlashRunning = CalcFlashDuration(z);
#ifdef DEBUG_F
Serial.println("nop Flash3");
#endif
break;
case 3:
digitalWrite(Flash4, HIGH); // switch on FlashLED on 8 o'clock position,
FlashOn[i] = true; // set flag and flash duration according to actuel stepspeedand
FlashRunning = CalcFlashDuration(z);
#ifdef DEBUG_F
Serial.print("Flash");Serial.print(i+1);Serial.print(" on, Duration:");
Serial.println(FlashRunning);
#endif break;
break;
case 4:
digitalWrite(Flash5, HIGH); // switch on FlashLED on 10 o'clock position,
FlashOn[i] = true; // set flag and flash duration according to actuel stepspeedand
FlashRunning = CalcFlashDuration(z);
#ifdef DEBUG_F
Serial.print("Flash");Serial.print(i+1);Serial.print(" on, Duration:");
Serial.println(FlashRunning);
#endif
break;
} // end switch case
} // end if, no else needed
} // end for loop
}
int CalcFlashDuration (int stepS) { // function to set duration of Flash
// according to turntable rotating speed
if (stepS > 4) return FlashDurFactor*1; // Flashduration FlashDurFactor times 20ms
if (stepS > 3) return FlashDurFactor*2; // Flashduration FlashDurFactor times 40ms
if (stepS > 2) return FlashDurFactor*3; // Flashduration FlashDurFactor times 60ms
return FlashDurFactor*4; // Flashduration FlashDurFactor times 80ms
} // function CalcFlashDuration closed