Jump to content

ffayolle

Members
  • Content Count

    287
  • Joined

  • Last visited

Community Reputation

693 Good

Profile Information

  • Location
    France
  • Interests
    7mm scale
    Narrow gauge

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. David, It sounds great... And I like your graphic Fabrice
  2. Hi all of you, All the best for 2020 Best regards from France, Fabrice
  3. Thanks for your sharing Very nice layout Fabrice
  4. Hi all of you, I've modified the Tokenless Block System program. I've added some comments to improve the understanding. This program includes IN&OUT datas for interlocking system. // Name #define NAME "Tokenless-Blocksystem" #define NAME2 "Tokenless block system for single track" #define NAME3 "with IN&OUT datas for interlocking system" // Version & Copyright #define VERSION "Version 2.0 (Arduino Uno)" #define COPYRIGHT "Copyright Fabrice Fayolle, August 2019" // A -> B : Down Line // B -> A : Up Line // Rail directions : Up Line -> To London / Down Line -> To the station // Arduino Uno // Pin -> Use for -> Connect to // 0 // 1 // 2 -> A:Normal -> Orange LED (Common - with a 470 ohms resistor) // 3 -> A:Blocked -> Red LED // 4 -> A:Accepted -> Green LED // 5 -> B:Normal -> Orange LED (Common - with a 470 ohms resistor) // 6 -> B:Blocked -> Red LED // 7 -> B:Accepted -> Green LED // 8 // 9 // 10 -> Block A->B (OUT) -> Interlocking System PCB // 11 -> Signal A (IN) -> Interlocking System PCB // 12 -> Block B->A (OUT) -> Interlocking System PCB // 13 -> Signal B (IN) -> Interlocking System PCB // 14 -> Lever input (B:Arrived) -> SPDT ON-(ON) // 15 -> Lever input (B:Offer) -> SPDT ON-(ON) // 16 -> Lever input (B:Normal/Accept)-> SPDT ON-ON // 17 -> Lever input (A:Arrived) -> SPDT ON-(ON) // 18 -> Lever input (A:Offer) -> SPDT ON-(ON) // 19 -> Lever input (A:Normal/Accept)-> SPDT ON-ON // INPUT // SPDT ON-ON // 1 -> 5V -> Accept // Common point // 2 -> GND -> Normal int A_Normal_Accept = 19; int B_Normal_Accept = 16; // SPDT ON-MON // 1 -> 5V // Common point // 2 -> GND -> Offer int A_Offer = 18; int B_Offer = 15; // SPDT ON-MON // 1 -> 5V // Common point // 2 -> GND -> Arrived int A_Arrived = 17; int B_Arrived = 14; // int A_Block_NOK = 10; int A_Signal_Not_Open = 11; int B_Block_NOK = 12; int B_Signal_Not_Open = 13; // Orange LED int A_Normal = 2; int B_Normal = 5; // Red LED int A_Blocked = 3; int B_Blocked = 6; // Green LED int A_Accepted = 4; int B_Accepted = 7; void setup() { Serial.begin(9600); Serial.println(NAME); Serial.println(NAME2); Serial.println(NAME3); Serial.println("-------------------------------------------------------------------------- -"); Serial.print(VERSION); Serial.print(", "); Serial.println(COPYRIGHT); Serial.println("---------------------------------------------------------------------------"); Serial.println(""); pinMode(A_Normal, OUTPUT); digitalWrite(A_Normal, LOW); pinMode(B_Normal, OUTPUT); digitalWrite(B_Normal, LOW); pinMode(A_Blocked, OUTPUT); digitalWrite(A_Blocked, LOW); pinMode(B_Blocked, OUTPUT); digitalWrite(B_Blocked, LOW); pinMode(A_Accepted, OUTPUT); digitalWrite(A_Accepted, LOW); pinMode(B_Accepted, OUTPUT); digitalWrite(B_Accepted, LOW); pinMode(A_Normal_Accept, INPUT_PULLUP); pinMode(B_Normal_Accept, INPUT_PULLUP); pinMode(A_Offer, INPUT_PULLUP); pinMode(B_Offer, INPUT_PULLUP); pinMode(A_Arrived, INPUT_PULLUP); pinMode(B_Arrived, INPUT_PULLUP); pinMode(A_Signal_Not_Open, INPUT_PULLUP); pinMode(A_Block_NOK, OUTPUT); digitalWrite(A_Block_NOK, HIGH); pinMode(B_Signal_Not_Open, INPUT_PULLUP); pinMode(B_Block_NOK, OUTPUT); digitalWrite(B_Block_NOK, HIGH); // Normalization of the block // Each signalman sets his block instrument to “Accept” (A_Normal_Accept and B_Normal_Accept to HIGH), provided no shunting is taking place into the block section. // The block status is indicated to both signalmen as “Normal” (A_Normal and B_Normal to LOW) if (digitalRead(A_Normal_Accept) == LOW || digitalRead(B_Normal_Accept) == LOW) { Serial.println("Error: To initialize the block system, please set both block instrument to Accept"); } while (digitalRead(A_Normal_Accept) == LOW || digitalRead(B_Normal_Accept) == LOW) { digitalWrite(A_Blocked, HIGH); digitalWrite(B_Blocked, HIGH); delay(250); digitalWrite(A_Blocked, LOW); digitalWrite(B_Blocked, LOW); delay(250); } digitalWrite(A_Normal, HIGH); digitalWrite(B_Normal, HIGH); Serial.println("Block system: OK"); } void loop() { while (digitalRead(A_Normal_Accept) == LOW && digitalRead(B_Normal_Accept) == LOW) { if (digitalRead(A_Offer) == LOW) { Serial.println("Error: A can't take the B offer because B is not set to Accept. Maybe shunting is taking place into the block section"); for (int i = 0; i < 4; i++) { digitalWrite(A_Normal, LOW); delay(250); digitalWrite(A_Normal, HIGH); delay(250); } } if (digitalRead(B_Offer) == LOW) { Serial.println("Error: B can't take the A offer because A is not set to Accept. Maybe shunting is taking place into the block section"); for (int i = 0; i < 4; i++) { digitalWrite(B_Normal, LOW); delay(250); digitalWrite(B_Normal, HIGH); delay(250); } } } // When the next train arrives at A, the A signalman sets his block instrument to “Normal” (A_Normal_Accept to LOW). // He then presses “Offer” (A_Offer to LOW). // At B, automatic acceptance of the train occurs, and the block status is indicated as “Blocked” (B_Blocked to HIGH). // If the B instrument were not set to “Accept” (B_Normal_Accept at HIGH), this would not occur, and a blinking warning would be given // When acceptance has occurred, the block status at A is indicated as “Accepted” (A_Accepted to HIGH). if ((digitalRead(A_Normal_Accept) == LOW) && (digitalRead(B_Normal_Accept) == HIGH) && (digitalRead(A_Offer) == LOW)) { Serial.println("Block system: A->B (accepting)"); digitalWrite(A_Normal, LOW); digitalWrite(A_Accepted, HIGH); digitalWrite(B_Normal, LOW); digitalWrite(B_Blocked, HIGH); // Block System releases the starting signal lever towards B (interlocking system). Serial.println("Block system: A->B (starting signal towards B interlocking system releasing)"); digitalWrite(A_Block_NOK, LOW); // Block System don't release the B starting signal lever towards A (interlocking system). digitalWrite(B_Block_NOK, HIGH); delay(250); // The A signalman may now, at any time, release his starting signal towards B. // As the signal clears (A_Signal_Not_Open at LOW), the block status changes to “Blocked” (A_Blocked to HIGH). Serial.println("Block system: A->B (waiting to open the starting signal towards B)"); while (digitalRead(A_Signal_Not_Open)) { } Serial.println("Block system: A->B (starting signal towards B opening)"); digitalWrite(A_Accepted, LOW); digitalWrite(A_Blocked, HIGH); delay(250); // The A signalman replaces his starting signal to danger once the train has departed from A (A_Signal_Not_Open at HIGH). Serial.println("Block system: A->B (waiting to close the starting signal towards B)"); while (!digitalRead(A_Signal_Not_Open)) { } Serial.println("Block system: A->B (starting signal towards B closing)"); // Block System cancels the releasing of the starting signal lever towards B (interlocking system). digitalWrite(A_Block_NOK, HIGH); delay(250); // The B signalman checks that the train has arrived complete at B (tail lamp) and then sets his block instrument to “Normal” (B_Normal to LOW). // He presses “Train Arrived” (B_Arrived to LOW). // The block section status is then restored to “Normal” (A_Normal and B_Normal at LOW) and indicated to both signalmen by “Normal” indications (A_Normal and B_Normal to LOW). while ((digitalRead(B_Arrived) != LOW) || (digitalRead(B_Normal_Accept) != LOW)) { } Serial.println("Block system: A->B (train arriving complete)"); Serial.println("Block system: OK"); digitalWrite(A_Blocked, LOW); digitalWrite(B_Blocked, LOW); digitalWrite(A_Normal, HIGH); digitalWrite(B_Normal, HIGH); } // When the next train arrives at B, the B signalman sets his block instrument to “Normal” (B_Normal_Accept to LOW). // He then presses “Offer” (B_Offer to LOW). // ... if ((digitalRead(B_Normal_Accept) == LOW) && (digitalRead(A_Normal_Accept) == HIGH) && (digitalRead(B_Offer) == LOW)) { digitalWrite(B_Normal, LOW); digitalWrite(B_Accepted, HIGH); digitalWrite(A_Normal, LOW); digitalWrite(A_Blocked, HIGH); digitalWrite(B_Block_NOK, HIGH); digitalWrite(A_Block_NOK, LOW); delay(250); while (digitalRead(B_Signal_Not_Open)) { } digitalWrite(B_Accepted, LOW); digitalWrite(B_Blocked, HIGH); delay(250); while (!digitalRead(B_Signal_Not_Open)) { } digitalWrite(B_Block_NOK, LOW); delay(250); while ((digitalRead(A_Arrived) != LOW) || (digitalRead(A_Normal_Accept) != LOW)) { } digitalWrite(B_Blocked, LOW); digitalWrite(A_Blocked, LOW); digitalWrite(B_Normal, HIGH); digitalWrite(A_Normal, HIGH); } } Keep in touch, Fabrice
  5. Hi all of you, Some news about my Arduino interlocking system: // SignalBox-Mega // Signal box (terminus station with single track) with "Nb_lever" levers // Signal box integrated interlocking system and tokenless block system (single track / terminus station) // Sound system -> Wtv020 // Digitrax LocoNet -> LocoNet // Tokenless Block System -> Tokenless // DCC Throttle -> Throttle // Accessories -> Accessories // Fabrice Fayolle, August 2016 // Version 2.1 for Arduino Mega // Signal box with "NB_lever" const int Nb_lever = 20; // Arduino Mega // Pin -> Use for -> Connect to // 0 // 1 // 2 -> Tokenless Up (IN) -> Tokenless PCB (Pin 12) // 3 -> Tokenless Signal Up (OUT) -> Tokenless PCB (Pin 13) // 4 // 5 -> Tokenless Signal Down (OUT) -> Tokenless PCB // 6 -> Default -> Red LED (with a 220 ohms resistor) // 9 -> Emergency Stop -> Push button // 10 -> Turntable direction -> SPDT ON-ON // 11 -> Turntable stop -> Push button // 12 -> Turntable low speed -> Push button // 13 -> Turntable mid speed -> Push button // 14 -> Loco start/stop -> Push button // 15 -> Loco whistle -> Push button // 16 to 21 -> Accessories -> SPDT ON-ON // 22 to 45 -> Lever Input -> SPDT ON-ON // 46 -> LocoNet Transmit pin -> Locoshield PCB Tx pin // 48 -> LocoNet Receive pin -> Locoshield PCB Rx pin // 47, 49, 51 and 53 -> Wtv020 -> Wtv020 PCB // INPUT // Emergency Stop : Push button // 1 -> Emergency Stop Pin // 2 -> GND // Lever : SPDT ON-ON // 1 -> 5V -> Normal position // Common point -> Lever Input Pin // 2 -> GND -> Reverse position // OUTPUT // Digitrax LocoNet message // Global constants and variables const boolean Activated = LOW; // Type lever table // 0 -> Not use // 1 -> Point // 2 -> FPL // 3 -> Signal // 4 -> Block signal const int Table_lever_type[Nb_lever] = {4, 3, 2, 1, 2, 1, 4, 3, 0, 3, 1, 3, 1, 1, 3, 3, 0, 0, 1, 3}; // Locking lever table to initialize each lock lever // 0 -> No lock // 1 -> 1 lock // x -> x locks // 99 -> not used lever const int Table_lever_lock[Nb_lever] = {0, 2, 0, 1, 0, 1, 1, 2, 99, 2, 0, 1, 0, 1, 0, 0, 99, 99, 0, 0}; // Interlocking system table (locking rules) // It's not necessary to simplify locking rules like with mechanical locking bars // 0 -> Nothing // 1 -> Lock // -1 -> Release // 1xx -> LWxxN (Lock When xx Normal) // -1xx -> RWxxN (Release When xx Normal) // 2xx -> LWxxR (Lock When xx Reverse) // -2xx -> RWxxR (Release When xx Reverse) // Special locking rules // 300 -> Lock When 4 is Normal and 6 is Normal // 400 -> Lock When 4 is Reverse and 19 is Reverse // -500 -> Release When 4 is Reverse and 11 is Reverse // -600 -> Release When 11 is Reverse and 19 is Reverse const int Table_interlocking[Nb_lever * Nb_lever] = { // Lever 1 (block signal) // locks 3, 5, 7, 11 // releases 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 2 (signal) // locks 3, 4, 5, 6, 8(6N), 10(6R), 11(4N&6N), 13 (4R), 14(4R), 15(4R), 19(4R), 20(4R&19R) // releases 0, 0, 1, 1, 1, 1, 0, 106, 0, 206, 300, 0, 204, 204, 204, 0, 0, 0, 204, 400, // Lever 3 (FPL) // locks 1, 7 // releases 2, 4, 8, 10 1, -1, 0, -1, 0, 0, 1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 4 (point) // locks 3, 6, 8, 16 // releases 2(11R&19R) 0, -600, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // Lever 5 (FPL) // locks 1, 7 // releases 2, 6, 8 1, -1, 0, 0, 0, -1, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 6 (point) // locks 4, 5, 8 // releases 2(11R), 10 0, -211, 0, 1, 1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 7 ( block signal) // locks 1, 3, 5, 11 // releases 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 8 (signal) // locks 2, 3, 4, 5, 6 // releases 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 9 (-) // not used 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 10 (signal) // locks 2, 3, 4, 5, 6 // releases 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 11 (point) // locks 1, 2(4N&6N), 7 // releases 12 1, 300, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 12 (signal) // locks 11, 16(14N) // releases 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 114, 0, 0, 0, 0, // Lever 13 (point) // locks // releases 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 14 (point) // locks 19 // releases 16(12R) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -212, 0, 0, 1, 0, // Lever 15 (signal) // locks 11, 12(11R), 13, 14, 16 , 19// releases 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 211, 1, 1, 0, 1, 0, 0, 1, 0, // Lever 16 (signal) // locks 2 (4R), 4, 11(14N), 12 (14N), 13, 14, 15, 19, 20(19R) // releases 0, 204, 0, 1, 0, 0, 0, 0, 0, 0, 114, 114, 1, 1, 1, 0, 0, 0, 1, 219, // Lever 17 (-) // not used 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 18 (-) // not used 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Lever 19 (point) // locks 15 // releases 14, 2(4R&11R) 0, -500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, // Lever 20 (signal) // locks 2 (4R&19R),4 (19R), 13 (19R), 14 (19R), 15(19R), 16(19R), 19 // releases 0, 400, 0, 219, 0, 0, 0, 0, 0, 0, 0, 0, 219, 219, 219, 219, 0, 0, 1, 0 }; // Visual management for interlocking system // Default lever position const int DefaultPin = 6; // Tokenless block system // Rail directions : Up Line -> To London / Down Line -> To the station boolean Block_ON = false; // Define which Arduino UNO Pin you use for communicate with the Tokenless PCB const int upBlock_request_PIN = 2; const int upBlock_signalopen_PIN = 3; const int downBlock_signalopen_PIN = 5; // Define which lever type you use for Block signal const int Block_signal = 4; // Define which lever (0 to xx) you use to control signal const int upSignal_lever = 6; const int downSignal_lever = 0; boolean upBlock_request = false; boolean upBlock_blocked = false; // Throttle // Define used slots table int used_SLOT[120]; // Define the address of the turntable DCC decoder const int ADR_Turntable = 101; // Define constants and variables for the turntable boolean TT_dir = false; const int TT_dir_PIN = 10; const int TT_stop_PIN = 11; const int TT_lowspeed_PIN = 12; const int TT_midspeed_PIN = 13; // Define the address of the loco DCC decoder const int ADR_Loco = 22; // Define constants and variables for the loco boolean Loco_On = false; const int Loco_start_stop_PIN = 14; const int Loco_whistle_PIN = 15; // LocoNet #include <LocoNet.h> // Define LocoNet Transmit Pin #define LN_TX_PIN 46 // Emergency Stop const int Emergency_PIN = 9; // Pointer to a received LocoNet packet lnMsg *LnPacket; // DDC Address of stationary decoder const int Table_lever_dcc[Nb_lever] = {1, 2, 3, 4, 11, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; void slot_Init() // Initiliaze all slots { for (int slot = 0; slot < 120; slot++) { sendOPC_xxx(OPC_RQ_SL_DATA, slot, 0); } } void sendOPC_x(int OPC_Type) // OPC_GPOFF - OPC_GPON - OPC_IDLE LocoNet Message { lnMsg SendPacket; SendPacket.data[0] = OPC_Type; LocoNet.send( &SendPacket ); switch (OPC_Type) { case OPC_GPOFF: // OPC_GPOFF -> Power OFF Serial.print("OPC_GPOFF"); break; case OPC_GPON: // OPC_GPON -> Power ON Serial.print("OPC_GPON"); break; case OPC_IDLE: // OPC_IDLE -> Emergency Stop Serial.print("OPC_IDLE"); break; } Serial.println(" LocoNet message sent"); delay(250); return; } void sendOPC_xxx(int OPC_Type, int Arg1, int Arg2) // OPC_LOCO_SPD - OPC_LOCO_DIRF - OPC_LOCO_SND - OPC_SW_REQ - OPC_MOVE_SLOTS - OPC_RQ_SL_DATA - OPC_LOCO_ADR LocoNet Message { lnMsg SendPacket; SendPacket.data[0] = OPC_Type; SendPacket.data[1] = Arg1; SendPacket.data[2] = Arg2; LocoNet.send( &SendPacket ); switch (OPC_Type) { case OPC_LOCO_SPD: // OPC_LOCO_SPD Serial.print ("SLOT "); Serial.print(Arg1); Serial.print(" : OPC_LOCO_SPD"); break; case OPC_LOCO_DIRF: // OPC_LOCO_DIRF Serial.print ("SLOT "); Serial.print(Arg1); Serial.print(" : OPC_LOCO_DIRF"); break; case OPC_LOCO_SND: // OPC_LOCO_SND Serial.print ("SLOT "); Serial.print(Arg1); Serial.print(" : OPC_LOCO_SND"); break; case OPC_SW_REQ: // OPC_SW_REQ Serial.print ("Turnout Adr "); Serial.print(Arg1 + 1); Serial.print(" : OPC_SW_REQ"); break; case OPC_MOVE_SLOTS: // OPC_MOVE_SLOTS Serial.print ("SLOT "); Serial.print(Arg1); Serial.print(" : OPC_MOVE_SLOTS"); break; case OPC_RQ_SL_DATA: // OPC_RQ_SL_DATA Serial.print ("SLOT "); Serial.print(Arg1); Serial.print(" : OPC_RQ_SL_DATA"); break; case OPC_LOCO_ADR: // OPC_LOCO_ADR Serial.print ("DCC Adr "); Serial.print(Arg2); Serial.print(" : OPC_LOCO_ADR"); break; } Serial.println(" LocoNet message sent"); delay(250); return; } void LocoNet_Message_For_Lever(int SLever_dcc, int SLever_type, boolean SLever_state) { int sw1 = 0x00; int sw2 = 0x00; switch (SLever_type) { case 0 : // 0 -> Not use break; case 1 : // 1 -> Point SLever_dcc = SLever_dcc - 1; if (SLever_state) { sw1 |= B00100000; sw2 |= B00100000; } sw1 |= B00010000; sw1 |= (SLever_dcc >> 7) & 0x0F; sw2 |= (SLever_dcc >> 7) & 0x0F; sendOPC_xxx(OPC_SW_REQ, SLever_dcc & 0x7F, sw1); sendOPC_xxx(OPC_SW_REQ, SLever_dcc & 0x7F, sw2); break; case 2: // 2 -> FPL break; case 3: // 3 -> Signal break; case 4: // 4 -> Block signal break; } return; } // Wtv020 #include <Wtv020sd16p.h> const int clockPin = 47; // CLOCK 7 const int resetPin = 49; // RESET 1 const int diPin = 51; // DATAIN 10 const int busyPin = 53; // BUSY 15 Wtv020sd16p wtv020sd16p(resetPin, clockPin, diPin, busyPin); // 0000.AD4 -> 0 -> Lever change // 0001.AD4 -> 1 -> Block system code bell // 0002.AD4 -> 2 -> People talking // 0003.AD4 -> 3 -> Steam engine // 0004.AD4 -> 4 -> People talking (2) // Wait the end of the sound before to do something else void Wtv020_wait() { delay(250); while (digitalRead(busyPin) == HIGH) { } return; } // Object "Throttle" class Throttle { private: int SLOT; int ADR; int SPD; int DIRF; int SND; public: void Setup(int SADR); void Change_SPD(int SSPD); void Change_DIRF(int SDIRF); void Change_SND(int SSND); } ; void Throttle::Setup(int SADR) { sendOPC_xxx(OPC_LOCO_ADR, 0, SADR); LnPacket = LocoNet.receive() ; while ((LnPacket->data[0] != 0xE7) | (LnPacket->data[4] != SADR)) { sendOPC_xxx(OPC_LOCO_ADR, 0, SADR); LnPacket = LocoNet.receive(); } Serial.print(LnPacket->data[0], HEX); Serial.print(" LocoNet Message Received -> DCC Adr "); Serial.print(LnPacket->data[4]); Serial.print(" was found in SLOT "); Serial.println(LnPacket->data[2]); SLOT = LnPacket->data[2]; ADR = LnPacket->data[4]; SPD = 0x00; DIRF = 0x00; SND = 0x00; sendOPC_xxx(OPC_MOVE_SLOTS, SLOT, SLOT); sendOPC_xxx(OPC_LOCO_DIRF, SLOT, DIRF); sendOPC_xxx(OPC_LOCO_SPD, SLOT, SPD); sendOPC_xxx(OPC_LOCO_SND, SLOT, SND); Serial.println("Communication initialized"); int i = 0; while (used_SLOT[i] != 0) { i = i + 1; } used_SLOT[i] = SLOT; return; } void Throttle::Change_SPD(int SSPD) { SPD = SSPD; Serial.print("SPD at "); Serial.print((SPD * 100) / 128); Serial.println("%"); sendOPC_xxx(OPC_LOCO_SPD, SLOT, SPD); } void Throttle::Change_DIRF(int SDIRF) { DIRF = DIRF + SDIRF; Serial.print("DIRF:"); Serial.print(DIRF); Serial.print("\t\tDirection: "); Serial.print(((DIRF & 0x20) == 0) ? "<-" : "->"); Serial.print("\tFunction(s): "); Serial.print(((DIRF & 0x10) == 0) ? "" : "F0 "); Serial.print(((DIRF & 0x01) == 0) ? "" : "F1 "); Serial.print(((DIRF & 0x02) == 0) ? "" : "F2 "); Serial.println(((DIRF & 0x04) == 0) ? "" : "F3"); sendOPC_xxx(OPC_LOCO_DIRF, SLOT, DIRF); } void Throttle::Change_SND(int SSND) { SND = SND + SSND; Serial.print("SND:"); Serial.println(SND); sendOPC_xxx(OPC_LOCO_DIRF, SLOT, SND); } Throttle TT_Throttle, Loco_Throttle; // Object "Lever" class Lever { private: int Lever_input; int Lever_type; int Lever_state; int Lever_lock; int Lever_dcc; public: void Setup(int SLever_input); boolean State_of_lever(); int Type_of_lever(); boolean Change_asking(); boolean Change_is_possible(); void Change(); void Change_lever_lock(int SChange); } ; void Lever::Setup(int SLever_input) { boolean Normal = true; boolean Reverse = false; // Input : from pin 22 to pin 45 Lever_input = SLever_input + 22; pinMode (Lever_input, INPUT); digitalWrite(Lever_input, HIGH); if (digitalRead(Lever_input) == Reverse) { delay(100); if (digitalRead(Lever_input) == Reverse) { digitalWrite(DefaultPin, HIGH); while (digitalRead(Lever_input) == Reverse) { } digitalWrite(DefaultPin, LOW); } } Lever_type = Table_lever_type[SLever_input]; // State of the lever // true -> Normal(by default) // false -> Reverse Lever_state = Normal; Lever_lock = Table_lever_lock[SLever_input]; Lever_dcc = Table_lever_dcc[SLever_input]; LocoNet_Message_For_Lever(Lever_dcc, Lever_type, true); return; } boolean Lever::Change_asking() { boolean result = false; if (digitalRead(Lever_input) != Lever_state) { delay(100); if (digitalRead(Lever_input) != Lever_state) { result = true; } } return result; } boolean Lever::Change_is_possible() { boolean result = false; result = (Lever_lock == 0); if (result == false) { while (digitalRead(Lever_input) != Lever_state) { digitalWrite(DefaultPin, HIGH); } digitalWrite(DefaultPin, LOW); } return result; } void Lever::Change() { Lever_state = !Lever_state; // Wtv020 wtv020sd16p.asyncPlayVoice(0); // LocoNet LocoNet_Message_For_Lever(Lever_dcc, Lever_type, Lever_state); // Wtv020 Wtv020_wait(); return; } boolean Lever::State_of_lever() { boolean result = true; result = Lever_state; return result; } int Lever::Type_of_lever() { int result = 0; result = Lever_type; return result; } void Lever::Change_lever_lock(int SChange) { Lever_lock += SChange; return; } Lever L[Nb_lever]; void setup() { // Initialize Serial Port USB at 57600 baud Serial.begin(57600); Serial.println("SignalBox-Mega Monitor"); // LocoNet LocoNet.init(LN_TX_PIN); pinMode(Emergency_PIN, INPUT); digitalWrite(Emergency_PIN, HIGH); DCC_On(); // Throttle // Initialize used_SLOT for (int i = 0; i < 120; i++) { used_SLOT[i] = 0; } // Initialize turntable INPUT pinMode(TT_dir_PIN, INPUT); digitalWrite(TT_dir_PIN, HIGH); pinMode(TT_stop_PIN, INPUT); digitalWrite(TT_stop_PIN, HIGH); pinMode(TT_lowspeed_PIN, INPUT); digitalWrite(TT_lowspeed_PIN, HIGH); pinMode(TT_midspeed_PIN, INPUT); digitalWrite(TT_midspeed_PIN, HIGH); // Initialize Turntable Throttle TT_Throttle.Setup(ADR_Turntable); // Initialize loco INPUT pinMode(Loco_start_stop_PIN, INPUT); digitalWrite(Loco_start_stop_PIN, HIGH); pinMode(Loco_whistle_PIN, INPUT); digitalWrite(Loco_whistle_PIN, HIGH); // Initialize Loco Throttle Loco_Throttle.Setup(ADR_Loco); // Wtv020 wtv020sd16p.reset(); delay(500); // If you want to adjust the speaker volume, modify on Wtv020sd16p library (Wtv020sd16p.cpp) // this constant VOLUME_MAX = 0xFFF7 (from 0xFFF0 to 0xFFF7) and use the unmute() function wtv020sd16p.unmute(); delay(500); // Visual management pinMode(DefaultPin, OUTPUT); digitalWrite(DefaultPin, LOW); // Accessories // Levers setup for (int i = 0; i < Nb_lever; i++) { L[i].Setup(i); } Serial.println("Ready to use"); // Wtv020 wtv020sd16p.asyncPlayVoice(2); // Tokenless pinMode(upBlock_request_PIN, INPUT); pinMode(upBlock_signalopen_PIN, OUTPUT); digitalWrite(upBlock_request_PIN, HIGH); digitalWrite(upBlock_signalopen_PIN, HIGH); pinMode(downBlock_signalopen_PIN, OUTPUT); digitalWrite(downBlock_signalopen_PIN, HIGH); Serial.println("Tokenless Block System : Normal"); } void loop() { for (int i = 0; i < Nb_lever; i++) { if (L[i].Change_asking()) { if (L[i].Change_is_possible()) { // Interlocking rules Locking_rules(i); // Change the state of the lever L[i].Change(); Serial.print("Lever "); Serial.print(i + 1); Serial.print(" changed to "); Serial.println(L[i].State_of_lever() ? "Normal" : "Reverse"); // Tokenless if ( i == upSignal_lever) { if (L[i].State_of_lever()) { if (Block_ON) { L[i].Change_lever_lock(1); Serial.print("Block System locks "); Serial.println(i + 1); upBlock_blocked = true; digitalWrite(upBlock_signalopen_PIN, HIGH); } } else { if (Block_ON) { digitalWrite(upBlock_signalopen_PIN, LOW); Serial.println("Tokenless Block System : UP -> Blocked"); } } } if ( i == downSignal_lever) { if (L[i].State_of_lever()) { digitalWrite(downBlock_signalopen_PIN, HIGH); Serial.println("Signal DOWN Line -> Closed"); } else { digitalWrite(downBlock_signalopen_PIN, LOW); Serial.println("Signal DOWN Line -> Open"); } } } else { Serial.print("Lever "); Serial.print(i + 1); Serial.println(" is locked"); } } } // Loconet Emergency(); // Tokenless upBlock_accept(); upBlock_normal(); // Throttle (turntable) Turntable_Order(); // Throttle (loco) Loco_Order(); } void Locking_rules(int Slever) // Apply interlocking system rules when you move a lever { int Shift = Slever * Nb_lever; if (L[Slever].State_of_lever()) // Lever on "Normal" position { for (int i = 0; i < Nb_lever; i++) { switch (Table_interlocking[Shift + i]) { case 0 : break; case -1 : // Releases L[i].Change_lever_lock(Table_interlocking[Shift + i]); Serial.print(Slever + 1); Serial.print(" releases "); Serial.println(i + 1); break; case 1 : // Locks L[i].Change_lever_lock(Table_interlocking[Shift + i]); Serial.print(Slever + 1); Serial.print(" locks "); Serial.println(i + 1); break; default : // Locks/Releases when xx Normal/Reverse Serial.print(Slever + 1); Serial.print(" locks/releases "); Serial.print(i + 1); L[i].Change_lever_lock(Conditionnal_locking(Table_interlocking[Shift + i])); ; } } } else // Lever on "Reverse" position { for (int i = 0; i < Nb_lever; i++) { switch (Table_interlocking[Shift + i]) { case 0 : break; case -1 : // Locks L[i].Change_lever_lock(-Table_interlocking[Shift + i]); Serial.print(Slever + 1); Serial.print(" locks "); Serial.println(i + 1); break; case 1 : // Releases L[i].Change_lever_lock(-Table_interlocking[Shift + i]); Serial.print(Slever + 1); Serial.print(" releases "); Serial.println(i + 1); break; default : // Releases/Locks when xx Normal/Reverse Serial.print(Slever + 1); Serial.print(" releases/locks "); Serial.print(i + 1); L[i].Change_lever_lock(-Conditionnal_locking(Table_interlocking[Shift + i])); ; } } } return; } int Conditionnal_locking (int Locking) // Verify lever position if interlocking system rule is Locks/Releases When Lever(s) xx is(are) Normal/Reverse { int Hundred = Locking / 100; int result = 0; switch (Hundred) { case 1 : // Locks when Lever (Locking-(HundredX100)) is Normal if (L[Locking - 101].State_of_lever()) { Serial.print(" because "); Serial.print(Locking - 100); Serial.println(" is Normal"); result = 1; } else { Serial.println(" -NA-"); } break; case -1 : // Releases when Lever (Locking-(HundredX100)) is Normal if (L[-Locking - 101].State_of_lever()) { Serial.print(" because "); Serial.print(-Locking - 100); Serial.println(" is Normal"); result = -1; } else { Serial.println(" -NA-"); } break; case 2 : // Locks when Lever (Locking-(HundredX100)) is Reverse if (!L[Locking - 201].State_of_lever()) { Serial.print(" because "); Serial.print(Locking - 200); Serial.println(" is Reverse"); result = 1; } else { Serial.println(" -NA-"); } break; case -2 : // Releases when Lever (Locking-(HundredX100)) is Reverse if (!L[-Locking - 201].State_of_lever()) { Serial.print(" because "); Serial.print(-Locking - 200); Serial.println(" is Reverse"); result = -1; } else { Serial.println(" -NA-"); } break; case 3 : // Locks when Lever 4 is Normal and Lever 6 is Normal if (L[4 - 1].State_of_lever() && L[6 - 1].State_of_lever()) { Serial.println(" because 4 is Normal and 6 is Normal"); result = 1; } else { Serial.println(" -NA-"); } break; case 4 : // Locks when Lever 4 is Reverse and Lever 19 is Reverse if (!L[4 - 1].State_of_lever() && !L[19 - 1].State_of_lever()) { Serial.println(" because 4 is Reverse and 19 is Reverse"); result = 1; } else { Serial.println(" -NA-"); } break; case -5 : // Releases when Lever 4 is Reverse and Lever 11 is Reverse if (!L[4 - 1].State_of_lever() && !L[11 - 1].State_of_lever()) { Serial.println(" because 4 is Reverse and 11 is Reverse"); result = -1; } else { Serial.println(" -NA-"); } break; case -6 : // Releases when Lever 11 is Reverse and Lever 19 is Reverse if (!L[11 - 1].State_of_lever() && !L[19 - 1].State_of_lever()) { Serial.println(" because 11 is Reverse and 19 is Reverse"); result = -1; } else { Serial.println(" -NA-"); } break; } return result; } void upBlock_accept() // Tokenless Block System on "Accepted" for Up Line { upBlock_request = digitalRead(upBlock_request_PIN); delay(100); if ( !upBlock_request && (!Block_ON && L[downSignal_lever].State_of_lever())) { // Wtv020 wtv020sd16p.asyncPlayVoice(1); Wtv020_wait(); Serial.println("Tokenless Block System : UP Line -> Accepted"); L[upSignal_lever].Change_lever_lock(-1); Serial.print("Block System releases "); Serial.println(upSignal_lever + 1); L[downSignal_lever].Change_lever_lock(1); Serial.print("Block System locks "); Serial.println(downSignal_lever + 1); Block_ON = true; } return; } void upBlock_normal() // Tokenless Block System on "Normal" { upBlock_request = digitalRead(upBlock_request_PIN); delay(100); if (L[upSignal_lever].State_of_lever()) { if ( upBlock_request && Block_ON ) { if (!upBlock_blocked) { L[upSignal_lever].Change_lever_lock(1); Serial.print("Block System locks "); Serial.println(upSignal_lever + 1); } upBlock_blocked = false; Block_ON = false; L[downSignal_lever].Change_lever_lock(-1); Serial.print("Block System releases "); Serial.println(downSignal_lever + 1); Serial.println("Tokenless Block System : Normal"); //Wtv020 wtv020sd16p.asyncPlayVoice(2); Wtv020_wait(); } } return; } void DCC_On() // DCC Power ON { sendOPC_x(OPC_GPOFF); sendOPC_x(OPC_GPON); return; } void Emergency() // Emergency Stop required { int i = 0; if (digitalRead(Emergency_PIN) == Activated) { delay(100); if (digitalRead(Emergency_PIN) == Activated) { while (digitalRead(Emergency_PIN) == Activated) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Serial.println("Emergency STOP!!!"); //sendOPC_x(OPC_IDLE); while (used_SLOT[i] != 0) { sendOPC_xxx(OPC_LOCO_SPD, used_SLOT[i], 0x00); i = i + 1; } } } return; } void Turntable_Order() // Control Turntable Direction by a SPDT ON-ON (Input: TT_dir_PIN) // and Turntable Speed by some Push buttons (Input: TT_stop_PIN, TT_lowspeed_PIN, TT_midspeed_PIN) { if ((digitalRead(TT_dir_PIN) == HIGH) && TT_dir) { TT_dir = false; TT_Throttle.Change_DIRF(-0x20); } if ((digitalRead(TT_dir_PIN) == LOW) && !TT_dir) { TT_dir = true; TT_Throttle.Change_DIRF(0x20); } if (digitalRead(TT_stop_PIN) == Activated) { delay(100); if (digitalRead(TT_stop_PIN) == Activated) { while (digitalRead(TT_stop_PIN) == Activated) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Serial.print("Turntable "); TT_Throttle.Change_SPD(0x00); } } if (digitalRead(TT_lowspeed_PIN) == Activated) { delay(100); if (digitalRead(TT_lowspeed_PIN) == Activated) { while (digitalRead(TT_lowspeed_PIN) == Activated) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Serial.print("Turntable "); TT_Throttle.Change_SPD(0x03); } } if (digitalRead(TT_midspeed_PIN) == Activated) { delay(100); if (digitalRead(TT_midspeed_PIN) == Activated) { while (digitalRead(TT_midspeed_PIN) == Activated) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Serial.print("Turntable "); TT_Throttle.Change_SPD(0x40); } } return; } void Loco_Order() // Control LOCO Sound by some Push buttons (Input: Loco_start_stop_PIN, Loco_whistle_PIN) { if ((digitalRead(Loco_start_stop_PIN) == LOW) && Loco_On == false) { delay(100); if ((digitalRead(Loco_start_stop_PIN) == LOW) && Loco_On == false) { while (digitalRead(Loco_start_stop_PIN) == LOW) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Loco_Throttle.Change_DIRF(0x10); delay(500); Loco_Throttle.Change_DIRF(0x08); delay(500); Loco_Throttle.Change_DIRF(-0x08); delay(3000); Loco_Throttle.Change_SND(0x01); delay(1500); Loco_Throttle.Change_SND(-0x01); delay(500); Loco_Throttle.Change_DIRF(0x01); delay(500); Loco_Throttle.Change_DIRF(-0x01); delay(500); Loco_Throttle.Change_DIRF(0x01); Loco_On = true; } } if ((digitalRead(Loco_start_stop_PIN) == LOW) && Loco_On == true) { delay(100); if ((digitalRead(Loco_start_stop_PIN) == LOW) && Loco_On == true) { while (digitalRead(Loco_start_stop_PIN) == LOW) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Loco_Throttle.Change_DIRF(-0x01); delay(1000); Loco_Throttle.Change_DIRF(-0x10); Loco_On = false; } } if ((digitalRead(Loco_whistle_PIN) == LOW) && Loco_On == true) { delay(100); if ((digitalRead(Loco_whistle_PIN) == LOW) && Loco_On == true) { while (digitalRead(Loco_whistle_PIN) == LOW) { digitalWrite(DefaultPin, HIGH); delay(100); digitalWrite(DefaultPin, LOW); delay(100); } Loco_Throttle.Change_DIRF(0x04); delay(250); Loco_Throttle.Change_DIRF(-0x04); } } return; } // Tokenless //Tokenless block system for single track // A -> B : Down Line // B -> A : Up Line // Rail directions : Up Line -> To London / Down Line -> To the station // Fabrice Fayolle, May 2016 // Version 1.0 for Arduino Uno // Arduino Uno // Pin -> Use for -> Connect to // 0 // 1 // 2 -> A:Normal -> Orange LED (Common + with a 470 ohms resistor) // 3 -> A:Blocked -> Red LED // 4 -> A:Accepted -> Green LED // 5 -> B:Normal -> Orange LED (Common + with a 470 ohms resistor) // 6 -> B:Blocked -> Red LED // 7 -> B:Accepted -> Green LED // 8 // 9 // 10 -> Up (OUT) -> Locoshield PCB // 11 -> Signal Up (IN) -> Locoshield PCB // 12 -> Down (OUT) -> Locoshield PCB (Uno -> Pin 2 / Mega -> Pin x) // 13 -> Signal Down (IN) -> Locoshield PCB (Uno -> Pin 3 / Mega -> Pin x) // 14 -> Lever input (B:Arrived) -> SPDT ON-(ON) // 15 -> Lever input (B:Offer) -> SPDT ON-(ON) // 16 -> Lever input (B:Normal/Accept)-> SPDT ON-ON // 17 -> Lever input (A:Arrived) -> SPDT ON-(ON) // 18 -> Lever input (A:Offer) -> SPDT ON-(ON) // 19 -> Lever input (A:Normal/Accept)-> SPDT ON-ON // INPUT // SPDT ON-ON // 1 -> 5V -> Normal // Common point // 2 -> GND -> Accept int A_Normal_Accept = 19; // SPDT ON-MON // 1 -> 5V // Common point // 2 -> GND -> Offer int A_Offer = 18; // SPDT ON-MON // 1 -> 5V // Common point // 2 -> GND -> Offer int A_Arrived = 17; // int B_Normal_Accept = 16; int B_Offer = 15; int B_Arrived = 14; // int A_Block_OK = 10; int A_Signal_Open = 11; int B_Block_OK = 12; int B_Signal_Open = 13; // Orange LED int A_Normal = 2; // Red LED int A_Blocked = 3; // Green LED int A_Accepted = 4; // int B_Normal = 5; int B_Blocked = 6; int B_Accepted = 7; void setup() { pinMode(A_Normal, OUTPUT); digitalWrite(A_Normal, HIGH); pinMode(B_Normal, OUTPUT); digitalWrite(B_Normal, HIGH); pinMode(A_Blocked, OUTPUT); digitalWrite(A_Blocked, HIGH); pinMode(B_Blocked, OUTPUT); digitalWrite(B_Blocked, HIGH); pinMode(A_Accepted, OUTPUT); digitalWrite(A_Accepted, HIGH); pinMode(B_Accepted, OUTPUT); digitalWrite(B_Accepted, HIGH); pinMode(A_Normal_Accept, INPUT); digitalWrite(A_Normal_Accept, HIGH); pinMode(B_Normal_Accept, INPUT); digitalWrite(B_Normal_Accept, HIGH); pinMode(A_Offer, INPUT); digitalWrite(A_Offer, HIGH); pinMode(B_Offer, INPUT); digitalWrite(B_Offer, HIGH); pinMode(A_Arrived, INPUT); digitalWrite(A_Arrived, HIGH); pinMode(B_Arrived, INPUT); digitalWrite(B_Arrived, HIGH); pinMode(A_Signal_Open, INPUT); digitalWrite(A_Signal_Open, HIGH); pinMode(A_Block_OK, OUTPUT); digitalWrite(A_Block_OK, HIGH); pinMode(B_Signal_Open, INPUT); digitalWrite(B_Signal_Open, HIGH); pinMode(B_Block_OK, OUTPUT); digitalWrite(B_Block_OK, HIGH); // Normalisation of the block // Each signalman sets his block instrument to “Accept” (A_Normal_Accept and B_Normal_Accept to HIGH), provided no shunting is taking place into the block section. // The block status is indicated to both signalmen as “Normal” (A_Normal and B_Normal to LOW) while (digitalRead(A_Normal_Accept) == LOW || digitalRead(B_Normal_Accept) == LOW) { digitalWrite(A_Blocked, LOW); digitalWrite(B_Blocked, LOW); delay(250); digitalWrite(A_Blocked, HIGH); digitalWrite(B_Blocked, HIGH); delay(250); } digitalWrite(A_Normal, LOW); digitalWrite(B_Normal, LOW); } void loop() { while (digitalRead(A_Normal_Accept) == LOW && digitalRead(B_Normal_Accept) == LOW) { if ((digitalRead(A_Offer) == LOW) || (digitalRead(B_Offer) == LOW)) { for (int i = 0; i < 4; i++) { digitalWrite(A_Normal, HIGH); digitalWrite(B_Normal, HIGH); delay(250); digitalWrite(A_Normal, LOW); digitalWrite(B_Normal, LOW); delay(250); } } } // When the next train arrives at A, the A signalman sets his block instrument to “Normal” (A_Normal_Accept to LOW). // He then presses “Offer” (A_Offer to LOW). // At B, automatic acceptance of the train occurs, and the block status is indicated as “Blocked” (B_Blocked to LOW). // If the B instrument were not set to “Accept” (B_Normal_Accept at HIGH), this would not occur, and a blinking warning would be given // When acceptance has occurred, the block status at A is indicated as “Accepted” (A_Accepted to LOW). if ((digitalRead(A_Normal_Accept) == LOW) && (digitalRead(B_Normal_Accept) == HIGH) && (digitalRead(A_Offer) == LOW)) { digitalWrite(A_Normal, HIGH); digitalWrite(A_Accepted, LOW); digitalWrite(B_Normal, HIGH); digitalWrite(B_Blocked, LOW); digitalWrite(A_Block_OK, LOW); delay(250); // The A signalman may now, at any time, release his starting signal towards B. // As the signal clears (A_Signal_Open at LOW), the block status changes to “Blocked” (A_Blocked to LOW). //while (digitalRead(A_Signal_Open) != LOW) //{ //} digitalWrite(A_Accepted, HIGH); digitalWrite(A_Blocked, LOW); delay(250); // The A signalman replaces his starting signal to danger once the train has departed from A (A_Signal_Open at HIGH). while (digitalRead(A_Signal_Open) == LOW) { } delay(250); // The B signalman checks that the train has arrived complete at B (tail lamp) and then sets his block instrument to “Normal” (B_Normal to LOW). // He presses “Train Arrived” (B_Arrived to LOW). // The block section status is then restored to “Normal” (A_Normal and B_Normal at LOW) and indicated to both signalmen by “Normal” indications (A_Normal and B_Normal to LOW). while ((digitalRead(B_Arrived) != LOW) || (digitalRead(B_Normal_Accept) != LOW)) { } digitalWrite(A_Blocked, HIGH); digitalWrite(B_Blocked, HIGH); digitalWrite(A_Normal, LOW); digitalWrite(B_Normal, LOW); digitalWrite(A_Block_OK, HIGH); } // When the next train arrives at B, the B signalman sets his block instrument to “Normal” (B_Normal_Accept to LOW). // He then presses “Offer” (B_Offer to LOW). // ... if ((digitalRead(B_Normal_Accept) == LOW) && (digitalRead(A_Normal_Accept) == HIGH) && (digitalRead(B_Offer) == LOW)) { digitalWrite(B_Normal, HIGH); digitalWrite(B_Accepted, LOW); digitalWrite(A_Normal, HIGH); digitalWrite(A_Blocked, LOW); digitalWrite(B_Block_OK, LOW); delay(250); while (digitalRead(B_Signal_Open) != LOW) { } digitalWrite(B_Accepted, HIGH); digitalWrite(B_Blocked, LOW); delay(250); while (digitalRead(B_Signal_Open) == LOW) { } delay(250); while ((digitalRead(A_Arrived) != LOW) || (digitalRead(A_Normal_Accept) != LOW)) { } digitalWrite(B_Blocked, HIGH); digitalWrite(A_Blocked, HIGH); digitalWrite(B_Normal, LOW); digitalWrite(A_Normal, LOW); digitalWrite(B_Block_OK, HIGH); } }
  6. Hi all of you, In progress with some new products of Cites Miniatures (railing and hollow brick wall) Happy Eastern from France Fabrice
  7. David, Rod, Thanks for your return Fabrice
  8. Hi all of you, I'm back. Something new, something blue,... Have a G'day, Fabrice
  9. Hi all of you, Happy new year from France So, I've finished some detail parts on the bed track. And currently, I've building a CdZ (the French Gauge O Guild) U-60 kit. To be continued... Fabrice
  10. Nice lasercut engine house :good:
  11. Well done... Could I take a ticket to ride, please? Fabrice
  12. Hi, Nice signal box Do you add a part of station building too? Fabrice
  13. Thanks Ernie for your comments Currently, I would like to know if my baseboard design is enough strong. Fabrice
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.