/*---------------------------------------------------------------------------- ** ** Lights.c ** ** Controls the LED patterns. The LEDs are in three phases with 20 or so ** LEDs in each phase. Each phase is controlled by a full bridge, and there ** are two control lines for each phase, 'Colour' and 'Brightness'. ** 'Colour' is the polarity, which when 0 results in a colour RED, and when ** 1 results in GREEN. It is connected to a PWM output pin however, so colours ** in between green and red can be generated simply by adjusting the PWM ** ratio. The 'Brightness' pins are also on PWM outputs, and so the ** brightness can be adjusted also. ** **--------------------------------------------------------------------------*/ #include #include "Onboard.h" #include "Hardware.h" #include "Commands.h" #define NUM_PHASES 3 #define NUM_SEQUENCES 8 #define MAX_CONTROL_STRING_LENGTH 60 // Phase enumertaion enum { A, B, C }; // Controlling globals static char AutoRepeat = FALSE; static char CurrentSequence = -1; static char RequiredSequence = -1; typedef struct { unsigned char Start; unsigned char End; unsigned int Duration; } TFade; typedef struct { int CurrentColour; int CurrentBrightness; int SequenceStringIndex; int Delay; TFade Colour; TFade Brightness; } TControl; TControl Control[NUM_PHASES] = { {0, 0, 0, 0, {0,0,0}}, {0, 0, 0, 0, {0,0,0}}, {0, 0, 0, 0, {0,0,0}} }; /*---------------------------------------------------------------------------- // // LIGHT SEQUENCE COMMANDS // // Ccc - Set to colour 'cc' // Bbb - Set brightness to 'bb' // Wtt - Wait for 'tt' time units. // Fbbcctt - Fade to colour 'cc' and brightness 'bb' in time // 'tt' time units. If 'bb' or 'cc' is '==', // leave same as before. // // // Each instruction is terminated by a space or the end of string. Extra // spaces in the sequence strings are ignored. Time units are in 100ms, so // 32 represents 3.2 seconds. // Colour values are 00 for green and FF for red. 80 is amber. // Brightness is 00 for off and FF for fully on. // ----------------------------------------------------------------------------*/ static const char c[3][2][2] = {{"00","00"},{"00","00"},{"00","00"}}; static const char Sequences[NUM_SEQUENCES][NUM_PHASES][MAX_CONTROL_STRING_LENGTH] = { // Sequence 0 // Emergeny red flash at ~1.7 Hz. Performed with autorepeat ON. { {"B00 CFF W03 BFF CFF W03"}, // Phase A {"B00 CFF W03 BFF CFF W03"}, // Phase B {"B00 CFF W03 BFF CFF W03"} // Phase C }, // Sequence 1 // Start off and build up over 1 second to full red, // then repeat for green and amber. Same all phases. { {"B00 Cff Fffff10 B00 C80 Fff8010 B00 C00 Fff0010"}, // Phase A {"B00 Cff Fffff10 B00 C80 Fff8010 B00 C00 Fff0010"}, // Phase B {"B00 Cff Fffff10 B00 C80 Fff8010 B00 C00 Fff0010"} // Phase C }, // Sequence 2 // Ripple red amber and green around perimiter, all at full brightness. // Fade green->amber->red->amber-> etc. 1 cycle takes 2 seconds. { {"Bff C00 Fff8005 Fffff05 Fff8005 Fff0005"}, // Phase A {"Bff C80 Fffff05 Fff8005 Fff0005 Fff8005"}, // Phase A {"Bff Cff Fff8005 Fff0005 Fff8005 Fffff05"} // Phase A }, // Sequence 3 // "Throbbing" red pulse on all phases. Fade on in 0.3s, // fade off in 0.7s, so pulse is at 1Hz. { {"B00 Cff Fffff03 F00ff07"}, // Phase A {"B00 Cff Fffff03 F00ff07"}, // Phase B {"B00 Cff Fffff03 F00ff07"} // Phase C }, // Sequence 4 // Undefined { {""}, // Phase A {""}, // Phase B {""} // Phase C }, // Sequence 5 // Undefined { {""}, // Phase A {""}, // Phase B {""} // Phase C }, // Sequence 6 // Undefined { {""}, // Phase A {""}, // Phase B {""} // Phase C }, // Sequence 7 // Undefined { {""}, // Phase A {""}, // Phase B {""} // Phase C }, }; #define Hex(x) ((toupper(x) > '9') ? (toupper(x) - 'A' + 10) : (x - '0')) /*---------------------------------------------------------------------------- // // StrToDec // // Convert a pointer to an ASCII hexadecimal 2-digit value to the value. // // Parameters: // Ptr Pointer to string of 6 characters as defined in sequence // string. // // Return Value: // -1 Character was '=' meaning same as current value. // 0-255 Conversion of hexadecimal value. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ int StrToDec(char *Ptr) { if (*Ptr == '=') return -1; else return (Hex(*Ptr) * 16 + Hex(*(Ptr+1))); } /*---------------------------------------------------------------------------- // // SetColour // // Sets the phase colour to the requested value, by adjusting the PWM ratio. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ void SetColour(char Phase, unsigned char Colour) { switch (Phase) { case A: LED_A_COLOUR = Colour; break; case B: LED_B_COLOUR = Colour; break; case C: LED_C_COLOUR = Colour; break; } } /*---------------------------------------------------------------------------- // // SetBrightness // // Sets the phase brightness to the requested value, by adjusting the PWM ratio. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ void SetBrightness(char Phase, unsigned char Brightness) { switch (Phase) { case A: LED_A_BRIGHTNESS = Brightness; break; case B: LED_B_BRIGHTNESS = Brightness; break; case C: LED_C_BRIGHTNESS = Brightness; break; } } /*---------------------------------------------------------------------------- // // ConfigureFade // // Sets the fade parameters to the required values. Note that the brightness // and colour fade over the same time period. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ void ConfigureFade(char Phase, char *Ptr) { int Duration, DestColour, DestBrightness; Duration = (*(Ptr+0) - '0') * 100 + (*(Ptr+1) - '0') * 10; // In 10ms units DestColour = StrToDec(Ptr+2); DestBrightness = StrToDec(Ptr+0); // Check for SAME AS CURRENT values if (DestColour == -1) DestColour = Control[Phase].CurrentColour; if (DestBrightness == -1) DestBrightness = Control[Phase].CurrentBrightness; // Set the brightness fade parameters Control[Phase].Brightness.Start = Control[Phase].CurrentBrightness; Control[Phase].Brightness.End = DestBrightness; Control[Phase].Brightness.Duration = Duration; // Set the colour fade parameters Control[Phase].Colour.Start = Control[Phase].CurrentColour; Control[Phase].Colour.End = DestColour; Control[Phase].Colour.Duration = Duration; // Set delay for the duration of this fade. Control[Phase].Delay = Duration; } /*---------------------------------------------------------------------------- // // GetInstruction // // Read the next instruction from the sequence string, and place it in the // destination string. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ char GetInstruction(char Phase, char *Dest) { char *Ptr; char Chr; Ptr = Dest; // Get past any preceding spaces while (Sequences[Phase][CurrentSequence][Control[Phase].SequenceStringIndex] == ' ') Control[Phase].SequenceStringIndex++; // Now starting at the next instruction... while (TRUE) { Chr = Sequences[Phase][CurrentSequence][Control[Phase].SequenceStringIndex]; // The next space indicates the end of the instruction if (Chr == ' ') return; // Check for end of string else if (Chr == 0) { if (AutoRepeat) { // If auto-repeat, start from the beginning of the string again. Control[Phase].SequenceStringIndex = 0; Ptr = Dest; } return FALSE; } // Another instruction character else *Ptr++ = toupper(Chr); } return TRUE; } /*---------------------------------------------------------------------------- // // RunSequence // // Lighting sequence. This takes the data structures above, and uses them // to run through a sequence string controlling the lights. // // Modification Record: // 27-Jul-00 Paul Hills First version. -----------------------------------------------------------------------------*/ void RunSequence(void) { unsigned char NextColour; unsigned char NextBrightness; char Inst[20]; int Phase; // // Don't bother if not running a sequence at the moment. // if (CurrentSequence == -1) return; // // For each of the phases... // for (Phase=0 ; Phase