Newer
Older
#include "powerproc.hpp"
MCP23S08 MCP(SS, MISO, MOSI, SCK);
// Semaphores for handling interrupts and power down events.
volatile byte MCP_ISR_FLAG = 0;
volatile byte PERFORM_PROCEDURE_FROM_INTERRUPT = 0;
void IRAM_ATTR isr() { MCP_ISR_FLAG = 1; }
void initializeMCP() {
pinMode(ISR_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ISR_PIN), isr, CHANGE);
// Enable inputs and interrupts on pins 0-2
MCP.pinMode8(0b00000111);
MCP.enableInterrupt(0, CHANGE);
MCP.enableInterrupt(1, CHANGE);
MCP.enableInterrupt(2, CHANGE);
// Inform SIB we're ready
MCP.write1(ALERT_SIB_PIN, HIGH);
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
if (MCP_ISR_FLAG == 0) {
return;
}
// False means triggered (not ok).
PINS.sib = false;
PINS.plc = false;
PINS.ups = false;
PINS.last_triggered = millis();
// Get the pins status at the time of the interrupt, and check their statuses.
Serial.print("Interrupt: ");
uint8_t regval = MCP.getInterruptCaptureRegister(); // INTCAP
Serial.print(regval, BIN);
uint8_t mask = 1 << 0;
if (!(regval & mask)) {
Serial.print(" UPS");
PINS.ups = true;
}
mask = 1 << 1;
if (!(regval & mask)) {
Serial.print(" PLC");
PINS.plc = true;
}
mask = 1 << 2;
if (!(regval & mask)) {
Serial.print(" SIB");
PINS.sib = true;
}
Serial.println();
// This interrupt was handled
MCP_ISR_FLAG = 0;
// If not all ok, set the power down flag, later handled.
if (!(PINS.sib && PINS.plc && PINS.ups)) {
PERFORM_PROCEDURE_FROM_INTERRUPT = 1;
PINS.canDoPowerFromREST = true;
PINS.sib = false;
PINS.plc = false;
PINS.ups = false;
int regval = MCP.read8();
}
mask = 1 << 1;
if (!(regval & mask)) {
}
mask = 1 << 2;
if (!(regval & mask)) {
}
Serial.println();
}
bool on = true;
unsigned long toggle_start = 0;
void toggle_status_led() {
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
void powerOffCheckLoop() {
if (!PERFORM_PROCEDURE_FROM_INTERRUPT) {
return;
}
// Disable interrupts while performing power procedure.
// Once we've been triggered, we perform the power down procedure, uninterrupted,
// regardless of changes in the environment.
detachInterrupt(digitalPinToInterrupt(ISR_PIN));
// Update status on serial interface and status webpage.
PINS.ramping = true;
Serial.println("POWERING DOWN DUE TO TRIGGER.");
// Inform SIB that we're about to perform a procedure.
MCP.write1(ALERT_SIB_PIN, LOW);
Serial.println("asked sib down");
// Wait for SIB to acknowledge by checking its input (should go to triggered).
/* This require hardware changes, not implemented yet.
// TODO: apply a timeout and go ahead anyway?
do {
delay(200);
poll_port_expander();
} while(!(PINS.sib));
Serial.println("SIB ACK");
*/
// Iterate through each group and power down.
String group;
String groups;
for (int8_t groupIdx = pproc.stagesCount - 1; groupIdx >= 0; groupIdx--) {
group = pproc.stages[groupIdx].name;
groups += group;
groups += ",";
PINS.stage = group;
pproc.powerOff(group);
delay(1000);
}
// Clear statuses on webpage and serial interfaces.
PINS.ramping = false;
Serial.print("Finished powering down from interrupt: ");
Serial.println(groups);
PINS.stage = "Ramped down";
// This event has been handled.
PERFORM_PROCEDURE_FROM_INTERRUPT = 0;
// Inform SIB that we're done and it can take data again.
MCP.write1(ALERT_SIB_PIN, HIGH);
// Re-enable interrupts before exiting.
attachInterrupt(digitalPinToInterrupt(ISR_PIN), isr, CHANGE);
}