const char *Version = "table driven signal controller - 260925a";
unsigned debug;
const char *SigStr [] = { "Nul", "Stop", "Approach", "Clear" };
char s [90];
// -----------------------------------------------------------------------------
// signal data structure
enum { L = 0, H = 1 };
enum { N = 0, R = 1 };
enum { Occ = 0, UnO = 1 };
enum { Nul, Stop, Approach, Clear };
const int8_t End = -1;
struct Cond {
int8_t pin;
bool cond;
};
struct Aspect {
uint8_t aspect;
Cond conds [3];
};
const int NpinsRYG = 3;
struct Sig {
const char *label;
int8_t PinsRYG [NpinsRYG ];
Aspect *aspects;
};
// -----------------------------------------------------------------------------
// input pins
const int8_t B_1 = 13;
const int8_t B_2 = 12;
const int8_t B_3 = A4;
const int8_t B_4 = A3;
const int8_t B_5 = A2;
const int8_t B_6 = A1;
const int8_t T1 = 8;
// outputs
const int8_t S1R = 9;
const int8_t S1Y = 10;
const int8_t S1G = 11;
const int8_t S2R = 4;
const int8_t S2Y = 5;
const int8_t S2G = 6;
const int8_t S4R = A5;
const int8_t S4Y = 2;
const int8_t S4G = 3;
// -----------------------------------------------
// ASCII diagram of a control point with 3 signals
//
// O-| S4
// _|________|_______|_
// / B_5 B_6
// /
// / O-| S2
// _|_______|__________/____|________|_______|_
// B_1 B_2 T1 B_3 B_4
// S1 |-O
// Each signal can display various aspects (e.g. Stop, Approach, Clear)
// depending on one or more conditions
// Conditions include turnout position (T1 N) and block occupancy
// Aspects are checked in most restrictive order
// N/R normal(straight) / reverse (diverging) turnout alignment,
// Occ occupied block, or
// H/L high/low, 1/0
// checks assume prior conditions not met
// if turnout condition R not met, N assumed in subsequent conditions
Aspect s2Aspects [] = {
{ Stop, { { T1, R }, End } },
{ Stop, { { B_2, Occ }, End } },
{ Approach, { { B_1, Occ }, End } },
{ }
};
Aspect s4Aspects [] = {
{ Stop, { { T1, N }, End } },
{ Stop, { { B_2, Occ }, End } },
{ Approach, { { B_1, Occ }, End } },
{ }
};
Aspect s1Aspects [] = {
{ Stop, { { T1, N }, { B_3, Occ }, End } },
{ Approach, { { T1, N }, { B_4, Occ }, End } },
{ Stop, { { T1, R }, { B_5, Occ }, End } },
{ Approach, { { T1, R }, End } },
{ }
};
// each signal is described in the following table
// label
// LED pins: red, yellow, green
// the Aspect table above for that signal
Sig sigs [] = {
{ "S1", { S1R, S1Y, S1G}, s1Aspects },
{ "S2", { S2R, S2Y, S2G}, s2Aspects },
{ "S4", { S4R, S4Y, S4G}, s4Aspects },
};
const int Nsig = sizeof(sigs)/sizeof(Sig);
// -----------------------------------------------------------------------------
bool
condsChk (
Aspect *asp )
{
if (debug) {
sprintf (s, " condsChk: %-9s", SigStr [asp->aspect]);
Serial.print (s);
}
// check all conditions
for (Cond *c = asp->conds; End != c->pin; c++) {
uint8_t cond = digitalRead (c->pin);
if (c->cond != cond) {
if (debug) {
sprintf (s, " pin %d ! %c", c->pin, c->cond ? 'H' : 'L');
Serial.println (s);
}
return false;
}
}
if (debug)
Serial.println (" true");
return true;
}
// -----------------------------------------------------------------------------
// check each aspect of a signal
int
sigChk (
Sig *sig )
{
if (debug) {
sprintf (s, " sigChk: %-9s", sig->label);
Serial.println (s);
}
for (Aspect *asp = sig->aspects ; Nul != asp->aspect; asp++) {
if (condsChk (asp)) {
return asp->aspect;
}
}
return Clear;
}
// -----------------------------------------------------------------------------
// set the signal aspect
enum { LedOff = HIGH, LedOn = LOW };
void
sigSet (
Sig *sig,
int red,
int yellow,
int green)
{
digitalWrite (sig->PinsRYG [0], red);
digitalWrite (sig->PinsRYG [1], yellow);
digitalWrite (sig->PinsRYG [2], green);
}
// -----------------------------------------------------------------------------
// check all signals
void sigsChk ()
{
if (debug)
Serial.println ("sigsChk:");
Sig *sig = sigs;
for (int n = 0; n < Nsig; n++, sig++) {
int aspect = sigChk (sig);
switch (aspect) {
case Stop:
sigSet (sig, LedOn, LedOff, LedOff);
break;
case Approach:
sigSet (sig, LedOff, LedOn, LedOff);
break;
case Clear:
sigSet (sig, LedOff, LedOff, LedOn);
break;
}
sprintf (s, " %20s %d %-9s", sig->label, n, SigStr [aspect]);
Serial.println (s);
}
Serial.println ();
}
// -----------------------------------------------------------------------------
// configure signal pins
void sigsInit ()
{
Sig *sig = sigs;
for (int n = 0; n < Nsig; n++, sig++) {
sprintf (s, " %s", sig->label);
Serial.println (s);
// output pins
for (int n = 0; n < NpinsRYG; n++) {
pinMode (sig->PinsRYG [n], OUTPUT);
sprintf (s, " out pin %2d", sig->PinsRYG [n]);
Serial.println (s);
}
// input pins
for (Aspect *asp = sig->aspects; Nul != asp->aspect; asp++) {
sprintf (s, " %-9s inputs ", SigStr [asp->aspect]);
Serial.print (s);
for (Cond *c = asp->conds; End != c->pin; c++) {
pinMode (c->pin, INPUT_PULLUP);
sprintf (s, " %2d", c->pin);
Serial.print (s);
}
Serial.println ();
}
}
}
// -----------------------------------------------------------------------------
unsigned long msec0;
void loop ()
{
unsigned long msec = millis ();
if (msec - msec0 >= 1000) {
Serial.println (msec);
msec0 = msec;
sigsChk ();
}
if (Serial.available ()) {
char buf [90];
int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
buf [n] = '\0';
char cmd;
int val;
sscanf (buf, "%c %d", &cmd, &val);
switch (cmd) {
case 'd':
debug = val;
break;
}
}
}
// -----------------------------------------------------------------------------
void setup ()
{
Serial.begin (115200);
Serial.println (Version);
sigsInit ();
}T
B_1
B_2
B_3
B_4
B_5
B_6