Block occupancy module

While slowly refining the signal controllers, I’ve developed a seperate block occupancy module – this uses a single Arduino Nano to monitor 8 blocks – feeding 8 digital signals to my main ‘control’ Arduino. More to come, but the sketch is available now on the Block Occupancy Module page

Undershelf rebuild continues

This weekend I built the first of the two replacement platforms, all done using the Metcalfe n-gauge platform kit.

Undershelf station rebuild

Following an increasing number of derailments on a curve at the exit to Undershelf station, I’ve decided to rebuild the corner at that end & the station itself. The following show the bridge & track being taken up & some flexi track showing roughly the new routing. I expect to have all the track back down by the end of next week.

track laid

Arduino based speed detector

speed detector

Someone posted on Facebook today a little box of tricks that you sit next to your track & it displays the scale speed of your trains as they go past.

Well this was too much temptation for me – I just had to see if I could make one. I have a heap of IR sensors left over from my experimentation with my first signal decoders.

So far I have everything made up on a breadboard & have written a sketch to make the necessary calculations. The sketch is based on having the sensors 120mm apart, I’ll try to make a more permanent circuit up over the weekend, measure the distance between the sensors & update the sketch.

This one can calculate speeds for OO or n gauge locos – i have one button to select the scale & one to reset the screen ready to measure the next train.

Parts:

Makerhawk OLED display

IR obstacle avoidance sensor x 2

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 0

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

Adafruit_SSD1306 display(OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2




#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =  {
  0x00,0x00,0x00,0x20,0x00,0x60,0x00,0xE0,0x00,0xE0,0xEE,0xCC,0x7E,0xCE,0x7F,0xDE,
  0x7F,0xFF,0x3F,0xFB,0x3B,0x33,0x11,0x27,0x00,0x0E,0x00,0x0E,0x00,0x0C,0x00,0x00
};

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif


int Distance = 120; //distance in mm between sensors

String Scale[]={"n","OO"};
int SelectedScale = 0;

int buttonApin = 6;
int buttonBpin = 7;
int SensorApin = 4;
int SensorBpin = 5;
bool Atripped = false;
bool Btripped = false;
long TimeElapsed;



void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  pinMode(buttonApin, INPUT_PULLUP);  
  pinMode(buttonBpin, INPUT_PULLUP); 
  pinMode(SensorApin, INPUT_PULLUP);  
  pinMode(SensorBpin, INPUT_PULLUP); 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  
  
  display.setTextSize(1);
  display.setTextColor(WHITE);
  ClearDisplay();
}

void loop() {
  // put your main code here, to run repeatedly:

  if (digitalRead(buttonApin) == LOW)
  {
    SetScale();
  }

  if (digitalRead(buttonBpin) == LOW)
  {
    Reset();
  }

  if (digitalRead(SensorApin)==LOW)
  {
    HandleSensor(0);
    
  }
  
  if (digitalRead(SensorBpin)==LOW)
  {
    HandleSensor(1);
  }
  
}

void HandleSensor(int SensorNum)
{
  if (SensorNum ==0)
  {
    if (Atripped)
    {
      //we've already handled sensor A
    }
    else
    {
      Atripped = true;
      display.setTextSize(1);
      display.setCursor(10,8);
      display.print ("A tripped");
      display.display();
      if (Btripped)
      {
        CalculateSpeed();
      }
      else
      {
        TimeElapsed=millis();
      }
    }
  }
  else if (SensorNum ==1)
  {
    if (Btripped)
    {
      //we've already handled sensor B
    }
    else
    {
      Btripped = true;
      display.setTextSize(1);
      display.setCursor(10,20);
      display.print ("B tripped");
      display.display();
      if (Atripped)
      {
        CalculateSpeed();
      }
      else
      
      {
        TimeElapsed=millis();
      }
    }
  }
}

void CalculateSpeed()
{
  float TimeTaken;
  float mmPerSecond; 
  float MPH;

  TimeTaken = (millis()-TimeElapsed);
  TimeTaken = TimeTaken/1000;

  Serial.print ("TimeTaken ");
  Serial.println (TimeTaken);
  mmPerSecond = Distance/TimeTaken ;
  Serial.print ("mmPerSecond ");
  Serial.println (mmPerSecond);
  
  MPH = mmPerSecond * 0.00223693629;
  if (SelectedScale == 0)
  {
    MPH = MPH * 148;
  }
  else
  {
    MPH = MPH * 76;
  }
  display.clearDisplay();
  
  display.setTextSize(2);
  display.setCursor(0,8);
  display.print (MPH);
  display.print (" MPH");
  display.display();
  
}

void Reset()
{
  Atripped=false;
  Btripped=false;
  TimeElapsed = 0;
  ClearDisplay();
}

void SetScale()
{
  SelectedScale++;
    if (SelectedScale>1)
    {
      SelectedScale=0;
    }
    Reset();
    
}

void ClearDisplay()
{
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.println(Scale[SelectedScale]);
  display.display();
  
}

British India Line restoration nears completion

Grafar Merchant Navy Locomotive British India Line

I bought this locomotive on ebay a few years ago as a non-runner. Over the past month I stripped the entire locomotive down to see what the problem was.

The first thing I discovered was that the cog that drives the wheels was severely worn, so a replacement 25-tooth gear was fitted. Once that was done & I’ fathomed out how all the gear rods go back together I found that some of them were snagging & causing the motor to pop up out of it’s seat. The first thing i tried was holding down the motor… So I replaced the newly stripped cog with another…

This time I was a little more careful putting it all back together & straightened out the rods that I believed were causing the issue. After about three or four hours of delicate rod bending the wheels were turning freely & I was able to refit the motor – tested on DC feed & it runs like a watch.

I’ve now fitted a DCC socket & ordered a Zimo MX616N decoder. I’ve chosen that one as it supports ABC braking & it’s tiny.

With any luck the decoder will arrive on Tuesday & she’ll be running again.

Shedend Railway Camera car

For those of you wondering what camera I used to get the footage riding around the railway, here is a link to the ebay listing.

The camera was loosely fitted to a coach with the roof removed & pushed around the railway by my 4mt locomotive. To get the trackside shots, I simply uncoupled the coach & placed it on the platform, or trackside. The camera creates a wifi hotspot, you connect to it with a mobile phone & use some very dodgy looking software to connect to it. Over the next month or so I’ll get some more footage & use floodlights to improve the lighting – that should also stop the glare from the signals, they’re not as bright as they look in the video, it’s just that the camera adjusts itself automatically to the light levels.

Signal Decoder #3 Sketch

Here’s he very latest sketch – this uses CT coils to detect block occupancy, which works a lot better than the original IR sensors. The board also now has a small OLED display attached – I haven’t found a good use for the display yet, but it looks cool.

use with decoder board #3

 

#include <DCC_Decoder.h>


#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include "arduino.h"


// signal controller #3 Andy Moore 18/06/2020

#define OLED_RESET 0

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

Adafruit_SSD1306 display(OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2


#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =  {
  0x00,0x00,0x00,0x20,0x00,0x60,0x00,0xE0,0x00,0xE0,0xEE,0xCC,0x7E,0xCE,0x7F,0xDE,
  0x7F,0xFF,0x3F,0xFB,0x3B,0x33,0x11,0x27,0x00,0x0E,0x00,0x0E,0x00,0x0C,0x00,0x00
};

static const unsigned char PROGMEM Shedend [] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFF, 0x80, 0x78, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFF, 0x00, 0x78, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFE, 0x00, 0x78, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFC, 0x1F, 0x78, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFC, 0x3F, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF,
0xFF, 0xFC, 0x3F, 0xF8, 0x61, 0xFE, 0x07, 0xF0, 0x43, 0xF0, 0x3E, 0x18, 0x7F, 0x04, 0x3F, 0xFF,
0xFF, 0xFC, 0x1F, 0xF8, 0x40, 0xF8, 0x03, 0xE0, 0x03, 0xC0, 0x1E, 0x10, 0x3E, 0x00, 0x3F, 0xFF,
0xFF, 0xFE, 0x07, 0xF8, 0x00, 0x70, 0x01, 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x3F, 0xFF,
0xFF, 0xFE, 0x01, 0xF8, 0x30, 0x70, 0xE0, 0xC3, 0x83, 0x87, 0x06, 0x0C, 0x1C, 0x38, 0x3F, 0xFF,
0xFF, 0xFF, 0x80, 0x78, 0x78, 0x61, 0xF0, 0x87, 0xC3, 0x0F, 0x86, 0x1E, 0x18, 0x7C, 0x3F, 0xFF,
0xFF, 0xFF, 0xE0, 0x78, 0x78, 0x60, 0x00, 0x87, 0xC3, 0x00, 0x06, 0x1E, 0x18, 0x7C, 0x3F, 0xFF,
0xFF, 0xFF, 0xF8, 0x38, 0x78, 0x60, 0x00, 0x87, 0xC3, 0x00, 0x06, 0x1E, 0x18, 0x7C, 0x3F, 0xFF,
0xFF, 0xFF, 0xFC, 0x38, 0x78, 0x61, 0xFF, 0x87, 0xC3, 0x0F, 0xFE, 0x1E, 0x18, 0x7C, 0x3F, 0xFF,
0xFF, 0xFD, 0xFC, 0x38, 0x78, 0x61, 0xFF, 0x87, 0xC3, 0x0F, 0xFE, 0x1E, 0x18, 0x7C, 0x3F, 0xFF,
0xFF, 0xFC, 0xF8, 0x38, 0x78, 0x70, 0xFD, 0x83, 0x83, 0x87, 0xEE, 0x1E, 0x18, 0x38, 0x3F, 0xFF,
0xFF, 0xFC, 0x00, 0x78, 0x78, 0x70, 0x01, 0xC0, 0x03, 0x80, 0x0E, 0x1E, 0x1C, 0x00, 0x3F, 0xFF,
0xFF, 0xFC, 0x00, 0xF8, 0x78, 0x78, 0x01, 0xE0, 0x03, 0xC0, 0x0E, 0x1E, 0x1E, 0x00, 0x3F, 0xFF,
0xFF, 0xFE, 0x01, 0xF8, 0x78, 0x7E, 0x03, 0xF0, 0xC3, 0xF0, 0x1E, 0x1E, 0x1F, 0x0C, 0x3F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

//------------------------------------------------------------------------------
// File generated by LCD Assistant
// http://en.radzio.dxp.pl/bitmap_converter/
//------------------------------------------------------------------------------


static const byte major =3;
static const byte minor =4;

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

const int SAMPLESIZE= 200;
int CurrentIndex=0;
long TimerVal=0;

String DecoderName = "Outer Loop";
String inputString = "";
bool stringComplete = false;

int CurrentSensor=0;
int CurrentSensorIndex=0;
long rms;

struct s_sensor
{
  int Pin;
  int EntrySignal;
  int ExitSignal;
  int PreviousSensor;
  bool Occupied; 
  byte TripCount=0;
};

struct s_DCCSignal
{
  int cv;
  int RedPin;
  int GreenPin;
  int RelayPin;
  int SemaphorePin;
  bool SignalSetToDanger;
  bool IsSemaphore;
  byte SemaphoreState;
  
};

const byte CLEAR = 0;
const byte DANGER = 1;
const byte C_UNKNOWN = 2;

const byte num_sensors = 5;
const byte num_signals = 5;

s_sensor sensors[num_sensors];
s_DCCSignal signals[num_signals];

//float RawData[num_sensors][SAMPLESIZE];

//int RelayPin=3;
//int ledPin = 5;
//int GreenPin = 6;
//int buttonApin = 9;
//int buttonBpin = 8;

//int latchPin = 11; 
//int clockPin = 10; 
//int dataPin = 12; 

//byte leds = 0;

unsigned long timer = 0;
unsigned long current_time = millis();
unsigned long SerialCounter =0;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0

//
// Setup
//
void setup() 
{
  int i;
  Serial.begin(9600);
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );  
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done


sbi (ADCSRA, 1) ;
cbi (ADCSRA, 0) ;
cbi (ADCSRA, 0) ;
 
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.clearDisplay();
 display.drawBitmap(0, 0,  Shedend, 128, 32,1);
//  display.display();
  display.display();
  delay(3000);
  display.clearDisplay();


  
  display.setTextSize(1);
  display.setTextColor(WHITE);

  int eePromIndex=0;
  byte tempMajor;
  EEPROM.get(eePromIndex,tempMajor);
  eePromIndex+=sizeof(tempMajor);
  byte  tempMinor;
  EEPROM.get(eePromIndex,tempMinor);
 
  inputString.reserve(40); 
  
  display.setTextSize(1);
  display.setTextColor(WHITE);
  
  
 
 display.println(DecoderName);
 display.println("                   ");
 display.print  ("sw ver:  ");
 display.print(major); 
 display.print        (".");
 display.print(minor);
 display.println          ("            ");
 
 display.display();

  if ((tempMajor==major) && (tempMinor==minor))
  {
     LoadConfig();
  }
  else
  {
     SetDefaults();
  }
  for (i=0;i<5;i++)
  {
    if (signals[i].IsSemaphore==true)
    {
      Serial.print("Signal ");
      Serial.print(i);
      Serial.println(" Semaphore");
      pinMode(signals[i].RelayPin,OUTPUT);
      pinMode(signals[i].SemaphorePin,OUTPUT);
      digitalWrite(signals[i].RelayPin,LOW);
      digitalWrite(signals[i].SemaphorePin,LOW);
       
    }
    else
    {
       Serial.print("Signal ");
      Serial.print(i);
      Serial.println(" two-aspect");
       pinMode(signals[i].RedPin,OUTPUT);
       pinMode(signals[i].GreenPin,OUTPUT);
    }
  }
 
}

void GetAnalog()
{
  int i;
  int temp;
  i=CurrentSensorIndex+10;
  
      for (CurrentSensorIndex;CurrentSensorIndex<i;CurrentSensorIndex++)
      {
        temp=analogRead(sensors[CurrentSensor].Pin);
        rms = rms+(temp*temp);
      }
      
     
             
}

void HandleSensor()
{
  GetAnalog();
  if(CurrentSensorIndex>=SAMPLESIZE)
  {
    rms=(sqrt(rms)*100)/(CurrentSensorIndex);
    if (rms<0)
    {
      rms=30;
    }
    Serial.print('\t');
    Serial.print(rms);
    if (rms > 20)
    {
      SensorTripped(CurrentSensor);
    }
    else
    {
      SensorClear(CurrentSensor);
    }
    
    CurrentSensorIndex=0;
    CurrentSensor++;
    rms=0;
    
    if (CurrentSensor==5)
    {
      CurrentSensor=0;
      Serial.println();
    }
  }
   
}


//==================================================
// 
//                  MAIN LOOP
//
//==================================================
void loop() 
{
  
 // display.clearDisplay();
 // display.setCursor(0,0);
  
  DCC.loop();

  if (millis()-TimerVal>20)
  {
    HandleSensor();
    TimerVal=millis();
   
  } 
  if (stringComplete)
  {
    HandleString();  
  }
}

void HandleString()
{
  if (inputString == "getName\n")
  {
    Serial.println(DecoderName);
  }
  else if (inputString == "getSensorConfig\n")
  {
    display.clearDisplay();
    display.setCursor(0,0);
    display.println("Sending sensor config");
    display.display();

    for (int i = 0;i<5;i++)
    {
       Serial.write(sensors[i].Pin);
       Serial.write(sensors[i].EntrySignal);
       Serial.write(sensors[i].ExitSignal);
       Serial.write(sensors[i].PreviousSensor);       
    }   
    
  }
  else if (inputString == "getSignalConfig\n")
  {
    display.println("Sending signal config");
    display.display();
    for (int i=0;i<5;i++)
    {
      Serial.write(signals[i].cv);
      Serial.write(signals[i].RedPin);
      Serial.write(signals[i].GreenPin);
      Serial.write(signals[i].SemaphorePin);
      Serial.write(signals[i].RelayPin);
      Serial.write(signals[i].IsSemaphore);
    }
  }
  else if (inputString == "setDefaults\n")
  {
    display.clearDisplay();
    display.setCursor(0,0);
    SetDefaults();
    SaveConfig();
  }
  else if (inputString =="saveConfig\n")
  {
    SaveConfig();
  }else if (inputString =="loadConfig\n")
  {
    LoadConfig();
  }
  else
  {
    display.println(inputString);
    display.display();   
  }
  inputString="";
  stringComplete = false;  
}

void SensorTripped(int SensorNum)
{
 
    sensors[SensorNum].TripCount=0;
    if (sensors[SensorNum].Occupied==false)
    {
     //  display.print("Sensor ");
     //  display.print(SensorNum);
     //  display.println(" tripped");
     //  display.display();
       sensors[SensorNum].Occupied=true;
    }
    SetSignalRed(sensors[SensorNum].EntrySignal);
  
  
 
}

void SensorClear(int SensorNum)
{
  if (sensors[SensorNum].TripCount > 2)
  {
    if (sensors[SensorNum].Occupied)
    {
       sensors[SensorNum].TripCount=0;
      // display.print("Sensor ");
      // display.print(SensorNum);
     //  display.println(" cleared");
     //  display.display();
       sensors[SensorNum].Occupied=false;
       //if (sensors[sensors[SensorNum].PreviousSensor].Occupied==false)
       {
         if (!signals[sensors[SensorNum].ExitSignal].SignalSetToDanger)
         {
            SetSignalGreen(sensors[SensorNum].ExitSignal);
         }
       } 
    }
  }
  else
  {
    sensors[SensorNum].TripCount++;
  }
}


void TwoAspectHandler(int signum, boolean enable)
{
  if (enable)
  {
    signals[signum].SignalSetToDanger = true;
    SetSignalRed(signum);
  }
  else
  {
    signals[signum].SignalSetToDanger = false;
    SetSignalGreen(signum);
  }
}
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
  // Convert NMRA packet address format to human address
  address -= 1;
  address *= 4;
  address += 1;
  address += (data & 0x06) >> 1;
  boolean enable = (data & 0x01) ? 1 : 0;
  // The DCC Accessory Address is now stored in "address" variable
  Serial.print(F("Basic addr: "));
  Serial.println(address, DEC);
  Serial.print(F("Activate Status: "));
  Serial.println(enable, DEC);

  for(int TempAdd = 0; TempAdd< num_signals; TempAdd++)
  {
    if(signals[TempAdd].cv == address)
    {
      Serial.print("Signal ");
      Serial.print(TempAdd,DEC);
      if (signals[TempAdd].IsSemaphore)
      {
        if (enable)
        {
          if (signals[TempAdd].SemaphoreState == DANGER)
          {
            //do nothing
          }
          else
          {
            pulseSignal( signals[TempAdd].SemaphorePin);
          }
          signals[TempAdd].SignalSetToDanger = true;
          signals[TempAdd].SemaphoreState = DANGER;
          digitalWrite(signals[TempAdd].RelayPin,LOW);
        
        }
        else
        {
          if (signals[TempAdd].SemaphoreState == DANGER)
          {
            pulseSignal(signals[TempAdd].SemaphorePin);
          }
          signals[TempAdd].SignalSetToDanger = false;
          signals[TempAdd].SemaphoreState = CLEAR;
          digitalWrite(signals[TempAdd].RelayPin,HIGH);              
        }  
      }
      else
      {
        TwoAspectHandler(TempAdd,enable);
      }
      
    }
    
  }
  if(address == 40)
  {
    //toggle semaphore
    pulseSignal( signals[1].SemaphorePin);
    
  }



}

void updateShiftRegister()
{ 
  //digitalWrite(latchPin, LOW); 
  //shiftOut(dataPin, clockPin, LSBFIRST, leds); 
  //digitalWrite(latchPin, HIGH);
}

void pulseSignal(int pinNum)
{
            //Serial.println("pulse signal");
            digitalWrite( pinNum,LOW);
            
            delay(300);
            digitalWrite( pinNum,HIGH);
            //DCC.loop();
            
}

void SetSignalRed(int Signum)
{

        if (signals[Signum].IsSemaphore)
        {
          if (signals[Signum].SignalSetToDanger)
          {
            //do nothing
          }
          else
          {
            if (signals[Signum].SemaphoreState == CLEAR)
            {
              //Serial.print("Pulse signal ");
              //Serial.print(Signum, DEC);
              //Serial.println(" To danger");
              pulseSignal( signals[Signum].SemaphorePin);
              signals[Signum].SemaphoreState = DANGER;
              digitalWrite(signals[Signum].RelayPin,LOW);
            }           
          }
        }
        else
        {
          //Serial.print(F("set signal Red: "));
          //Serial.println(Signum, DEC);
          //analogWrite(signals[Signum].RelayPin, 0);
         // Serial.print("Redpin = ");
          //Serial.println(signals[Signum].RedPin);
          digitalWrite(signals[Signum].RedPin,LOW);
          digitalWrite(signals[Signum].GreenPin,HIGH);
          
        }
}

void SetSignalGreen(int Signum)
{
  if (signals[Signum].IsSemaphore)
        {
          if (signals[Signum].SignalSetToDanger)
          {
            //do nothing
          }
          else
          {
            if (signals[Signum].SemaphoreState == DANGER)
            {
          //    Serial.print("Pulse signal ");
          //    Serial.print(Signum, DEC);
         //     Serial.println(" To clear");
              pulseSignal( signals[Signum].SemaphorePin);
              signals[Signum].SemaphoreState = CLEAR;
              digitalWrite(signals[Signum].RelayPin,HIGH);
            }
          }
        }
        else
        {
         //Serial.print(F("SetSignalGreen: "));
         //Serial.println(Signum, DEC);
         //analogWrite(signals[Signum].RelayPin, 255);
          digitalWrite(signals[Signum].RedPin,HIGH);
          digitalWrite(signals[Signum].GreenPin,LOW);
        }
}

void serialEvent()
{
  display.clearDisplay();
  display.setCursor(0,0);
  while(Serial.available())
  {
     char inchar=(char)Serial.read();
     inputString+= inchar;
     if (inchar =='\n')
     {
       stringComplete = true;
     }
   }
  
}

void SetDefaults()
{
  
  display.println("Setting defaults");
  display.display();
  //display.println("configuring sensors");
  //display.display();
  sensors[0].Pin = A0;
  sensors[0].EntrySignal = 0;
  sensors[0].ExitSignal = 0;
  sensors[0].PreviousSensor = 2;
  
  sensors[1].Pin = A1;
  sensors[1].EntrySignal = 2;
  sensors[1].ExitSignal = 2;
  sensors[1].PreviousSensor = 3;

  sensors[2].Pin = A2;
  sensors[2].EntrySignal = 4;
  sensors[2].ExitSignal = 4;
  sensors[2].PreviousSensor = 1;

  sensors[3].Pin = A3;
  sensors[3].EntrySignal = 1;
  sensors[3].ExitSignal = 1;
  sensors[3].PreviousSensor = 4;

  sensors[4].Pin = A6;
  sensors[4].EntrySignal = 3;
  sensors[4].ExitSignal =3;
  sensors[4].PreviousSensor = 0;
  //display.println("configuring signals");
 // display.display();
  signals[0].cv = 7;  
  signals[0].RedPin = 12;
  signals[0].GreenPin =3;
  signals[0].SemaphorePin = 0;
  signals[0].SignalSetToDanger = false;
  signals[0].RelayPin = 8;
  signals[0].IsSemaphore = false;
 // pinMode(signals[0].RedPin,OUTPUT);
 // pinMode(signals[0].GreenPin,OUTPUT);
  
  signals[1].cv = 8;  
  signals[1].RedPin = 10;
  signals[1].GreenPin = 11;
  signals[1].SemaphorePin = 8;
  signals[1].SignalSetToDanger = false;
  signals[1].RelayPin = 7;
  signals[1].IsSemaphore = true;
  signals[1].SemaphoreState = C_UNKNOWN;

  signals[2].cv=20;
  signals[2].RedPin = 10;
  signals[2].GreenPin = 11;
  signals[2].SemaphorePin = 0;
  signals[2].SignalSetToDanger = false;
  signals[2].RelayPin = 7;
  signals[2].IsSemaphore = false;
  signals[2].SemaphoreState = C_UNKNOWN;
 // pinMode(signals[2].RedPin,OUTPUT);
 // pinMode(signals[2].GreenPin,OUTPUT);

  signals[3].cv=21;
  signals[3].RedPin = 6;
  signals[3].GreenPin = 9;
  signals[3].SemaphorePin = 0;
  signals[3].SignalSetToDanger = false;
  signals[3].RelayPin = 7;
  signals[3].IsSemaphore = false;
  signals[3].SemaphoreState = C_UNKNOWN;
 // pinMode(signals[3].RedPin,OUTPUT);
 // pinMode(signals[3].GreenPin,OUTPUT);
  
  signals[4].cv=22;
  signals[4].RedPin = 4;
  signals[4].GreenPin = 5;
  signals[4].SemaphorePin = 0;
  signals[4].SignalSetToDanger = false;
  signals[4].RelayPin = 7;
  signals[4].IsSemaphore = false;
  signals[4].SemaphoreState = C_UNKNOWN;

  
 // pinMode(signals[4].RedPin,OUTPUT);
 // pinMode(signals[4].GreenPin,OUTPUT);
}

void SaveConfig()
{
  
    
  display.println("Saving Config");
  display.display();
 
  int eeAddress=0;
  
  EEPROM.put(eeAddress,major);
  eeAddress+=sizeof(major);
  
  EEPROM.put(eeAddress,minor);
  eeAddress+=sizeof(minor);
  EEPROM.put(eeAddress,sensors);
  eeAddress+=sizeof(sensors);
 
  EEPROM.put(eeAddress,signals);
  eeAddress+=sizeof(signals);
  
  display.println("Config saved");
  display.display();

  
}
void LoadConfig()
{
 
    display.println("Loading Config");
    display.display();
  int eeAddress=0;
  EEPROM.get(eeAddress,major);
  Serial.println(major);
  eeAddress+=sizeof(major);
  EEPROM.get(eeAddress,minor);
  eeAddress+=sizeof(minor);
  EEPROM.get(eeAddress,sensors);
  eeAddress+=sizeof(sensors);
  EEPROM.get(eeAddress,signals);
  display.println("Config loaded");
    display.display();
}