-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAutoCloseSM.cpp
113 lines (101 loc) · 3.55 KB
/
AutoCloseSM.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "AutoCloseSM.h"
#include "DoorSM.h" // need doorstate to initialize state
// Constructor
AutoCloseSM::AutoCloseSM() {
autoCloseTimer.reset(new Timer(HOLDING_TIME, &AutoCloseSM::onTimeout, *this, true));
}
void AutoCloseSM::init(DoorState_t doorState, std::bitset<SIZE_OF_FLAGS_ENUM> *flags){
// initialize state
switch(doorState) {
case DOOR_CLOSING:
transitionTo(WAITING_FOR_DOOR_CLOSED);
break;
case DOOR_CLOSED:
transitionTo(WAITING_FOR_DOG);
break;
case DOOR_OPEN:
if(flags->test(SENSOR_INRANGE_FLAG)) {
// there's a dog present, so wait for the allclear
transitionTo(WAITING_FOR_ALL_CLEAR);
}else{
flags->set(COMMAND_CLOSE_FLAG); // time to close the door (this avoids having to hold door open if no dog is present on init)
transitionTo(WAITING_FOR_DOOR_CLOSED);
}
break;
case DOOR_OPENING:
transitionTo(WAITING_FOR_DOOR_OPEN);
break;
}
// consume exit event so we don't do this the first time we enter runSM()
isExit = false;
}
/*********************** STATE MACHINE **************************************/
void AutoCloseSM::runSM(std::bitset<SIZE_OF_FLAGS_ENUM> *flags) {
switch(currentState) {
case WAITING_FOR_DOG:
if(flags->test(SENSOR_INRANGE_FLAG)) { // dog is present, so open door
flags->set(COMMAND_OPEN_FLAG);
transitionTo(WAITING_FOR_DOOR_OPEN);
}
break;
case WAITING_FOR_DOOR_OPEN:
if(flags->test(SWITCH_UPPER_FLAG)) { // door opened, so go to waiting for all clear
transitionTo(WAITING_FOR_ALL_CLEAR);
}
break;
case WAITING_FOR_ALL_CLEAR:
if(!flags->test(SENSOR_INRANGE_FLAG)) { // dog is not present, so go to holding door open
transitionTo(HOLDING_DOOR_OPEN);
}
break;
case HOLDING_DOOR_OPEN:
if(isEntry) {
isEntry = false;
autoCloseTimer->changePeriod(HOLDING_TIME);
autoCloseTimer->start(); // start the timer
}
if(flags->test(SENSOR_INRANGE_FLAG)) { // sensor was triggered again, so wait for all clear
transitionTo(WAITING_FOR_ALL_CLEAR);
}
if(timeoutOccurred) {
timeoutOccurred = false; // clear flag
flags->set(COMMAND_CLOSE_FLAG); // time to close the door
transitionTo(WAITING_FOR_DOOR_CLOSED);
}
if(isExit) {
autoCloseTimer->stop();
}
break;
case WAITING_FOR_DOOR_CLOSED:
if(flags->test(SWITCH_LOWER_FLAG)) {
transitionTo(WAITING_FOR_DOG);
}else if(flags->test(SWITCH_UPPER_FLAG)) {
//transitionTo(WAITING_FOR_DOOR_OPEN);
}else if(flags->test(SWITCH_BUMPER_FLAG)) {
transitionTo(WAITING_FOR_DOOR_OPEN); // don't worry about sending a door open command, that's handled by DoorSM
}else if(flags->test(SENSOR_INRANGE_FLAG)) { // dog triggered sensor again, so go back to opening
flags->set(COMMAND_OPEN_FLAG);
transitionTo(WAITING_FOR_DOOR_OPEN);
}
break;
}
// ensure that isExit is false, if there were exit actions they should have been resolved by here
if(isExit) {
isExit = false;
}
}
AutoCloseState_t AutoCloseSM::getState() {
return currentState;
}
void AutoCloseSM::transitionTo(AutoCloseState_t to) {
char message[100];
sprintf(message, "AutoCloseSM: Transitioning from %s to %s", AutoCloseStateNames[currentState].c_str(), AutoCloseStateNames[to].c_str());
Serial.println(message);
Particle.publish("Log", message);
currentState = to;
isEntry = true;
isExit = true;
}
void AutoCloseSM::onTimeout() {
timeoutOccurred = true;
}