diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..93ac46c263ebd958f70048477bc0700df6596dd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pioenvs diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000000000000000000000000000000000000..41867f4b88b5abbea15139806197994bf429a363 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,4 @@ +[env:uno] +platform = atmelavr +board = uno +framework = arduino diff --git a/src/PhoneNetwork.cc b/src/PhoneNetwork.cc new file mode 100644 index 0000000000000000000000000000000000000000..4df13bab73becbf611dd31e3714ddb2affeb60bc --- /dev/null +++ b/src/PhoneNetwork.cc @@ -0,0 +1,83 @@ +#include "PhoneNetwork.hh" + +PhoneNetwork::PhoneNetwork() :m_state(WAITING), m_switch(), m_communication({-1, -1}) { +} + +void PhoneNetwork::changeState(State targetState) { + switch(m_state) { + case(WAITING): + break; + case(DIALING): + break; + case(RINGING): + m_switch.stop_ring(); + break; + case(COMMUNICATING): + break; + } + + + switch(targetState) { + case(WAITING): + Serial.println("Move to state WAITING\n"); + m_switch.resetLines(); + break; + case(DIALING): + Serial.println("Move to state DIALING\n"); + m_communication.caller = m_switch.getActiveLine(); + m_switch.setLineMode(DIALING, m_communication.caller); + break; + case(RINGING): + Serial.println("Move to state RINGING\n"); + m_switch.setLineMode(RINGING, m_communication.called); + m_switch.start_ring(); + break; + case(COMMUNICATING): + Serial.println("Move to state COMMUNICATING\n"); + m_switch.setLineMode(COMMUNICATING, m_communication.called, m_communication.caller); + break; + } + m_state = targetState; +} + + +void PhoneNetwork::run() { + m_switch.refreshLinesState(); + Serial.println(String(m_switch.m_linesState[0]) + + String(m_switch.m_linesState[1]) + + String(m_switch.m_linesState[2])); + + switch(m_state) { + case(WAITING): + if(m_switch.phoneUnhooked()) { + changeState(DIALING); + } + break; + + case(DIALING): + m_communication.called = m_switch.getDialedLine(m_communication.caller); + if(m_switch.dialedComplete(m_communication.called)){ + changeState(RINGING); + } + else if (!m_switch.phoneUnhooked()) { + changeState(WAITING); + } + break; + + case(RINGING): + m_switch.ring(); + if(m_switch.phoneUnhooked(m_communication.called)) { + changeState(COMMUNICATING); + } + else if (!m_switch.phoneUnhooked()) { + changeState(WAITING); + } + break; + + case(COMMUNICATING): + if(!m_switch.phoneUnhooked(m_communication.caller)){ + changeState(WAITING); + } + break; + } +} diff --git a/src/PhoneNetwork.hh b/src/PhoneNetwork.hh new file mode 100644 index 0000000000000000000000000000000000000000..d196a9e5f4ff567a8a9192c926e16cb4630deb86 --- /dev/null +++ b/src/PhoneNetwork.hh @@ -0,0 +1,26 @@ +#ifndef PHONE_NETWORK_HH_INCLUDED +#define PHONE_NETWORK_HH_INCLUDED + +#include "constants.hh" +#include "Switch.hh" +#include "Arduino.h" + +struct Communication { + int called; + int caller; +}; + +class PhoneNetwork { +public: + PhoneNetwork(); + void changeState(State targetState); + void run(); + Switch m_switch; + +private: + State m_state; + Communication m_communication; + int m_dialedNumber[NUM_SIZE]; +}; + +#endif // PHONE_NETWORK_HH_INCLUDED diff --git a/src/Switch.cc b/src/Switch.cc new file mode 100644 index 0000000000000000000000000000000000000000..818c447d11f0b57ec881c284364d473d00d12c57 --- /dev/null +++ b/src/Switch.cc @@ -0,0 +1,193 @@ +#include "Switch.hh" + +//TODO: change initialisation to variable length table +Switch::Switch(){ + for(int i = 0; i<N_LINE ; i++) + { + m_linesState[i] = false; + } + refreshLinesState(); +} + +int Switch::searchPhoneBook(int number[NUM_SIZE]){ + for(int line=0; line<N_LINE; line++){ + + bool match=true; + for(int i=0; i<NUM_SIZE; i++){ + if(number[i] != linesNum[line][i]){ + match=false; + break; + } + } + + if(match) + return line; + } + + return -1; +} + +bool Switch::refreshLinesState(){ + bool hasChanged=false; + + for(int i=0; i<N_LINE; i++){ + //Line is considered active if the maximum duration of time HIGH (inactive) is less than 10ms (50Hz). + //This is like that to prevent false detect introduced by the ringing. + unsigned long highTime = pulseIn(linePin[i].state, HIGH, 50e3); + bool active = (highTime==0) ? (!digitalRead(linePin[i].state)) : (highTime < 10e3); + //Serial.println(String(i) + " is high for "+String(highTime)+"us -> =0? "+String(highTime==0)+" state: "+String(!digitalRead(linePin[i].state))+" ==>"+String(active)); + if(m_linesState[i] != active) + hasChanged = true; + m_linesState[i] = active; + } + + return hasChanged; +} + +int Switch::getDialedLine(int caller){ + int called = -1; + int number[NUM_SIZE] = {0}; + + //called = (caller+1)%N_LINE; + for(int i=0; i<NUM_SIZE; i++){ + number[i] = getDialedDigit(caller); + Serial.print(number[i]); + } + Serial.println(); + + called = searchPhoneBook(number); + + return called; +} + + +bool Switch::dialedComplete(int line) { + return line != -1; +} + +void Switch::start_ring() { + m_tps = millis(); + digitalWrite(MASTER_RING, HIGH); +} + +void Switch::ring(){ +// bool ringing=false; + +// ringing = millis() < (m_tps+RING_ON_TIME); +// if(millis() > (m_tps+RING_ON_TIME+RING_OFF_TIME)) { +// m_tps = millis(); +// } +// digitalWrite(MASTER_RING, ringing); +} + +void Switch::stop_ring() { + digitalWrite(MASTER_RING, LOW); +} + + +int Switch::getDialedDigit(int caller){ + bool done=false; + unsigned long tps; + int number=0; + + //Wait until begin of dialing + while(!digitalRead(linePin[caller].state)); + delay(PULSE_WIDTH/8); //Force blind to avoid bouncing detection + + while(not done){ + tps=millis(); + + number++; + + //HIGH state + while(digitalRead(linePin[caller].state) && not done) + done = millis() > (tps+PULSE_PAUSE); + delay(PULSE_WIDTH/8); //Force blind to avoid bouncing detection + + //LOW state + while(!digitalRead(linePin[caller].state) && not done) + done = millis() > (tps+PULSE_PAUSE); + delay(PULSE_WIDTH/8); //Force blind to avoid bouncing detection + } + + if(number == 10) number=0; + + return number; +} + +int Switch::getActiveLine(){ + int active = -1; + + refreshLinesState(); + + for(int i=0; i<N_LINE; i++){ + if(m_linesState[i] == true) + active = i; + } + return active; +} + +bool Switch::phoneUnhooked(int line) { + if(line != -1) { + return m_linesState[line] == true; + } + + for(int i=0; i < N_LINE; i++) { + if(m_linesState[i] == true) { + return true; + } + } + return false; +} + +void Switch::setLineMode(State state, int lineA, int lineB){ + if(lineA < 0) + { + return; + } + switch(state){ + case WAITING: + digitalWrite(linePin[lineA].selector, LOW); + digitalWrite(linePin[lineA].ring, LOW); + digitalWrite(linePin[lineA].negative, LOW); + digitalWrite(linePin[lineA].positive, LOW); + break; + case RINGING: + digitalWrite(linePin[lineA].selector, LOW); + digitalWrite(linePin[lineA].ring, HIGH); + digitalWrite(linePin[lineA].negative, LOW); + digitalWrite(linePin[lineA].positive, LOW); + break; + case DIALING: + digitalWrite(linePin[lineA].selector, HIGH); + digitalWrite(linePin[lineA].ring, LOW); + digitalWrite(linePin[lineA].negative, LOW); + digitalWrite(linePin[lineA].positive, HIGH); + break; + case COMMUNICATING: + digitalWrite(linePin[lineA].selector, HIGH); + digitalWrite(linePin[lineA].ring, LOW); + digitalWrite(linePin[lineA].negative, LOW); + digitalWrite(linePin[lineA].positive, HIGH); + + digitalWrite(linePin[lineB].selector, HIGH); + digitalWrite(linePin[lineB].ring, LOW); + digitalWrite(linePin[lineB].negative, HIGH); + digitalWrite(linePin[lineB].positive, LOW); + break; + } + delay(LINEMODE_DELAY); +} + +void Switch::resetLines(){ + for(int i=0; i<N_LINE; i++){ + setLineMode(WAITING, i); + } +} + +void Switch::printState(){ + for(int i=0; i<N_LINE; i++){ + Serial.println(String(i) + " is currently " + (m_linesState[i]?"active":"inactive")); + } + Serial.println(); +} diff --git a/src/Switch.hh b/src/Switch.hh new file mode 100644 index 0000000000000000000000000000000000000000..dc8ab770defd128c5dba02bd88f578fa429e6cb9 --- /dev/null +++ b/src/Switch.hh @@ -0,0 +1,33 @@ +#ifndef SWITCH_HH_INCLUDED +#define SWITCH_HH_INCLUDED + +#include "constants.hh" +#include "Arduino.h" + +class Switch +{ +public: + Switch(); + int searchPhoneBook(int number[NUM_SIZE]); + bool refreshLinesState(); + int getDialedLine(int caller); + bool dialedComplete(int line); + void start_ring(); + void ring(); + void stop_ring(); + int getDialedDigit(); + int getActiveLine(); + int getDialedDigit(int caller); + bool phoneUnhooked(int line = -1); + bool phonesHooked(int line = -1) return ! phoneUnhooked(line); + void setLineMode(State state, int lineA, int lineB=-1); + void resetLines(); + int m_linesState[N_LINE]; + +private: + unsigned long m_tps; + + void printState(); +}; + +#endif // SWITCH_HH_INCLUDED diff --git a/src/constants.hh b/src/constants.hh new file mode 100644 index 0000000000000000000000000000000000000000..77b9f52bc940c65f6301edfa6ca9d23512b52391 --- /dev/null +++ b/src/constants.hh @@ -0,0 +1,43 @@ +#ifndef CONSTANTS_HH_INCLUDED +#define CONSTANTS_HH_INCLUDED + +//Standard +#define RING_ON_TIME 1500 //ms +#define RING_OFF_TIME 3500 //ms +#define PULSE_WIDTH 100 //ms +#define PULSE_PAUSE 700 //ms +#define NUM_SIZE 3 //Number of digits in number + +//Hardware definition +#define N_LINE 3 + +//Pins definition +#define MASTER_RING 19 + +#define LINEMODE_DELAY 500 + +typedef struct { + int selector; + int ring; + int negative; + int positive; + int state; +} linepin_t; + +const linepin_t linePin[N_LINE] = { + {.selector= 2, .ring= 4, .negative= 6, .positive= 8, .state=14}, + {.selector= 3, .ring= 5, .negative= 7, .positive= 9, .state=15}, + {.selector=10, .ring=11, .negative=12, .positive=13, .state=16} +}; + +//Lines number +const int linesNum[N_LINE][NUM_SIZE] = { + {5,8,8}, + {2,3,6}, + {5,9,6} +}; + +//Differents states of a line +enum State {WAITING, RINGING, DIALING, COMMUNICATING}; + +#endif // CONSTANTS_HH_INCLUDED diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..4087f187fef481c489f2122ca26e9255a6481de5 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,32 @@ +#include "Arduino.h" +#include "PhoneNetwork.hh" +#include "constants.hh" + + +inline void setOutput(int pin){ + digitalWrite(pin, LOW); + pinMode(pin, OUTPUT); +} + +auto phoneNetwork = PhoneNetwork(); + +void setup() { + + //Setting up pins + for(int i=0; i<N_LINE; i++){ + setOutput(linePin[i].selector); + setOutput(linePin[i].ring); + setOutput(linePin[i].negative); + setOutput(linePin[i].positive); + pinMode(linePin[i].state, INPUT_PULLUP); + } + setOutput(MASTER_RING); + phoneNetwork.m_switch.resetLines(); + + Serial.begin(115200); + Serial.println("Small RTC, at your service !"); +} + +void loop() { + phoneNetwork.run(); +}