Skip to content
Snippets Groups Projects
Commit c4ae947a authored by Ziggy Vergne's avatar Ziggy Vergne
Browse files

Merge branch 'feature/state_machine' into 'master'

feat: add state machine phone network

See merge request !1
parents 58162249 2791563d
Branches master
No related tags found
1 merge request!1feat: add state machine phone network
.pioenvs
[env:uno]
platform = atmelavr
board = uno
framework = arduino
#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;
}
}
#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
#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();
}
#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
#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
#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();
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment