-
Notifications
You must be signed in to change notification settings - Fork 0
/
QueueMaster.h
179 lines (152 loc) · 5.29 KB
/
QueueMaster.h
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
114
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
168
169
170
171
172
173
174
175
176
177
178
179
/*
* To allow proper read of different controller ports and buttons,
* each channel needs to be measured seperately. This is done through a
* multiplexer that controlled with 2 outputs, giving 2x4 channels.
*
* First 1x4 channels are 1YN on the multiplexer and second 1x4 channels
* are 2YN. These are called queues below. This means there are 2 parallell
* queues with 4 channels each.
*
* The QueueMaster has Queuers on these queues and channels and runs their
* loops when it's their turn.
*/
#ifndef QUEUEMASTER_H
#define QUEUEMASTER_H
#include <HomeSpan.h>
#include "Config.h"
#include "Queuer.h"
struct QueueMaster {
int nbrOfChannels = 1; // will get increased during initiation.
uint32_t timer=millis();
int outputGpioPins[2];
int sampleInterval;
int currentChannel = -1;
int lastCompletedChannel = -1;
int maxNbrOfChannels = 4; // same as nbr of rows in arrays below
Queuer* registeredQueuers[4][2] = {0}; // [maxNbrOfChannels][maxNbrOfQueues]
QueueMaster(const int outputGpioPins[2], int sampleInterval) {
this->outputGpioPins[0] = outputGpioPins[0];
this->outputGpioPins[1] = outputGpioPins[1];
this->sampleInterval = sampleInterval;
setPinsForChannel(0);
}
void loop() {
if (currentChannel > -1) {
if (queuerIsBusy()) {
runQueuerLoop();
return;
} else {
LOG2("done with cycle "); LOG2(lastCompletedChannel); LOG2("\n");
prepareNextChannel();
return;
}
}
if(millis() - timer > (sampleInterval / nbrOfChannels)) {
activateNextChannel();
};
}
Queuer* getCurrentChannelQueuer(int i) {
if (currentChannel > -1) {
if (registeredQueuers[currentChannel][i] != 0) {
return registeredQueuers[currentChannel][i];
}
}
return 0;
}
bool queuerIsBusy() {
for(int i = 0; i < 2; i++) {
if (getCurrentChannelQueuer(i) == 0) continue;
if (!getCurrentChannelQueuer(i)->finishedWithTasks) return true;
}
return false;
}
void runQueuerLoop() {
for(int i = 0; i < 2; i++) {
if (getCurrentChannelQueuer(i) == 0) continue;
getCurrentChannelQueuer(i)->loop();
}
}
void resetQueuers() {
for(int i = 0; i < 2; i++) {
if (getCurrentChannelQueuer(i) == 0) continue;
getCurrentChannelQueuer(i)->reset();
}
}
void addQueuer(Queuer* queuer, int channel, bool useSecondaryQueue) {
LOG2("Adding queuer to channel "); LOG2(channel); LOG2(" in secondary "); LOG2(useSecondaryQueue); LOG2("\n");
const int queueNbr = useSecondaryQueue ? 1 : 0;
const int suggestedNbrOfChannels = channel + 1;
if (suggestedNbrOfChannels > this->nbrOfChannels) {
this->nbrOfChannels = suggestedNbrOfChannels;
}
registeredQueuers[channel][queueNbr] = queuer;
}
Queuer* getAnyQueuer(int channel, bool useSecondaryQueue) {
const int queueNbr = useSecondaryQueue ? 1 : 0;
if (channel > maxNbrOfChannels || channel < 0) {
LOG1("WARNING: channel out of allowed range. Channel: "); LOG1(channel); LOG1(" max number of channels: "); LOG1(maxNbrOfChannels); LOG1("\n");
return 0;
}
Queuer* q = registeredQueuers[channel][queueNbr];
if (q == 0) {
LOG1("WARNING: there is no queuer for this channel: "); LOG1(channel); LOG1(" and queue number: "); LOG1(queueNbr); LOG1("\n");
return 0;
}
return q;
}
int nextChannelNbr() {
if (lastCompletedChannel >= this->nbrOfChannels - 1) {
return 0;
}
return (lastCompletedChannel + 1);
}
void prepareNextChannel() {
lastCompletedChannel = currentChannel;
resetQueuers();
currentChannel = -1;
const int channelToPrepare = nextChannelNbr();
LOG2("preparing for channel "); LOG2(channelToPrepare); LOG2("\n");
setPinsForChannel(channelToPrepare);
timer = millis(); // reset timer to cause next cycle to start after a delay relative to this.
}
void activateNextChannel() {
if (currentChannel >= 0) {
LOG1("WARNING: last channel was not read properly or not at all. faking last channel read"); LOG1("\n");
prepareNextChannel();
// NOTE: we want to continue as nothing happened after preparing.
}
currentChannel = nextChannelNbr();
// skip cycle if there are no readers for that channel (shouldn't happen):
if (getCurrentChannelQueuer(0) == 0 && getCurrentChannelQueuer(1) == 0) {
LOG1("WARNING: No registered readers for next cycle. skipping..."); LOG1("\n");
prepareNextChannel();
activateNextChannel();
return;
}
}
void setPinsForChannel(int channel) {
// NOTE: should be binary, i.e. 0,0 0,1 1,0 1,1 but something fishy is going on that
// is left unfixed.
if (channel == -1) { // binary 0
digitalWrite(outputGpioPins[0], LOW);
digitalWrite(outputGpioPins[1], LOW);
}
if (channel == 0) { // binary 1
digitalWrite(outputGpioPins[0], HIGH);
digitalWrite(outputGpioPins[1], HIGH);
}
if (channel == 1) { // binary 2
digitalWrite(outputGpioPins[0], HIGH);
digitalWrite(outputGpioPins[1], LOW);
}
if (channel == 2) { // binary 3
digitalWrite(outputGpioPins[0], LOW);
digitalWrite(outputGpioPins[1], HIGH);
}
if (channel == 3) { // binary 4
digitalWrite(outputGpioPins[0], LOW);
digitalWrite(outputGpioPins[1], LOW);
}
}
};
#endif