Mercurial > hg > beaglert
comparison include/DigitalChannelManager.h @ 354:1b23300f3e78 prerelease
DigitalChannelManager takes care of managing digital channels for libpd/Heavy use
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Wed, 08 Jun 2016 21:11:36 +0100 |
parents | |
children | 1b053bc0a4b5 |
comparison
equal
deleted
inserted
replaced
353:bec5d43e4e7a | 354:1b23300f3e78 |
---|---|
1 /* | |
2 * DigitalStream.h | |
3 * | |
4 * Created on: 7 Jun 2016 | |
5 * Author: giulio | |
6 */ | |
7 | |
8 #ifndef DIGITALCHANNELMANAGER_H_ | |
9 #define DIGITALCHANNELMANAGER_H_ | |
10 #include <Bela.h> | |
11 | |
12 /** | |
13 * This class manages the digital channels. | |
14 * | |
15 * Each channel can be set as either signal or message rate. | |
16 * When set as message rate: | |
17 * inputs are parsed when calling processInput() and a callback | |
18 * is invoked when they change state, outputs are set via calls to setValue() and then written | |
19 * to the output array when calling processOutput(). | |
20 * | |
21 * When set at signal rate: | |
22 * the DigitalChannelManager only sets the pin direction. | |
23 * | |
24 * Throughout the class we keep track of message/signal rate | |
25 * and input/output in separate variables, so that we | |
26 * always know if a channel is managed by the DigitalChannelManager | |
27 * or not. This way, managed and unmanaged channels can be freely mixed in the code. | |
28 * | |
29 * For the reasons above, isSignalRate(channel) is not the same as !isMessageRate(channel) | |
30 * and isInput(channel) is not the same as !isOutput(channel) | |
31 * | |
32 */ | |
33 | |
34 class DigitalChannelManager { | |
35 public: | |
36 DigitalChannelManager(); | |
37 | |
38 /** | |
39 * Set the callback. | |
40 * | |
41 * The callback will be called when one of the managed message-rate input bits | |
42 * changes state. The callback's signature is | |
43 * void (*stateChangedCallback)(bool value, unsigned int delay, void* arg) | |
44 * where \c value is the new value of the channel, \c delay is the sample in the most | |
45 * recent block when the status changed, and \c arg is an additional argument passed | |
46 * to the callback, which can be set for each channel using setCallbackArgument() | |
47 * | |
48 */ | |
49 | |
50 void setCallback(void (*newCallback)(bool, unsigned int, void*)){ | |
51 stateChangedCallback = newCallback; | |
52 if(newCallback != NULL){ | |
53 callbackEnabled = true; | |
54 } else { | |
55 callbackEnabled = false; | |
56 } | |
57 }; | |
58 | |
59 /** | |
60 * Sets the argument for the callback. | |
61 * | |
62 * Typically an argument will allow the callback to identify the channel | |
63 * that changed state. | |
64 * | |
65 * @param channel is the channel for which the argument is set | |
66 * @param arg is the argument that will be passed to the callback for that channel | |
67 */ | |
68 void setCallbackArgument(unsigned int channel, void* arg){ | |
69 callbackArguments[channel] = arg; | |
70 } | |
71 | |
72 /** Process the input signals. | |
73 * | |
74 * Parses the input array and looks for state changes in the bits | |
75 * managed as message-rate inputs and invokes the | |
76 * appropriate callbacks. | |
77 * | |
78 * @param the array of input values | |
79 * @length the length of the array | |
80 * | |
81 */ | |
82 void processInput(uint32_t* array, unsigned int length){ | |
83 if(callbackEnabled == false){ | |
84 return; | |
85 } | |
86 // DIGITAL_FORMAT_ASSUMPTION | |
87 static uint16_t lastDigitalInputValues = 0; | |
88 for (unsigned int frame = 0; frame < length; ++frame) { | |
89 uint32_t inWord = array[frame]; | |
90 uint16_t direction = inWord & 0Xffff; | |
91 uint16_t inputValues = (inWord >> 16); | |
92 // note: even though INPUT == 0 and OUTPUT == 0, this is actually reversed in the binary word, | |
93 // so it actually is 1 for input and 0 for output | |
94 | |
95 // mask out outputValues from the half-word by setting them to zero | |
96 // if a bit of direction is 1, then it is an input. | |
97 // ANDing this with the inputValues gets rid of the output values | |
98 inputValues &= direction; | |
99 uint16_t changed = inputValues ^ lastDigitalInputValues; | |
100 //mask out channels that are not set at message rate | |
101 changed &= messageRate; | |
102 if(changed){ | |
103 // rt_printf("changed: 0x%x, messageRate: 0x%x, ANDed: 0x%x\n", changed, messageRate, changed&messageRate); | |
104 for(int n = 0; n < 16; ++n){ | |
105 if(changed & (1 << n)){ //if state for this channel has changed, invoke the callback | |
106 stateChangedCallback(inputValues & (1 << n), frame, callbackArguments[n]); | |
107 } | |
108 } | |
109 } | |
110 lastDigitalInputValues = inputValues; | |
111 } | |
112 } | |
113 | |
114 /** Process the output signals. | |
115 * | |
116 * Processes the output array and appropriately sets the | |
117 * bits managed as message-rate outputs. | |
118 * Bits marked as input and unmanaged bits are left alone. | |
119 * | |
120 * It also updates the channel directions. | |
121 * | |
122 * @param the array of input values | |
123 * @length the length of the array | |
124 * | |
125 */ | |
126 void processOutput(uint32_t* array, unsigned int length){ | |
127 uint32_t orWord = ((setDataOut << 16) | modeInput); | |
128 uint32_t andWord = ~((clearDataOut << 16) | modeOutput); | |
129 uint32_t outWord; | |
130 for (unsigned int frame = 0; frame < length; ++frame) { | |
131 outWord = array[frame]; | |
132 outWord = outWord | orWord; | |
133 outWord = outWord & andWord; | |
134 array[frame] = outWord; | |
135 } | |
136 } | |
137 | |
138 /** | |
139 * Inquires if the channel is managed as signal-rate. | |
140 * | |
141 * @param channel the channel which is inquired. | |
142 */ | |
143 bool isSignalRate(unsigned int channel){ | |
144 return (bool)((1 << channel) & signalRate); | |
145 } | |
146 | |
147 /** | |
148 * Inquires if the channel is managed as message-rate. | |
149 * | |
150 * @param channel the channel which is inquired. | |
151 * @return true if the channel is managed at message-rate, false otherwise | |
152 */ | |
153 bool isMessageRate(unsigned int channel){ | |
154 return (bool)((1 << channel) & messageRate); | |
155 } | |
156 | |
157 /** | |
158 * Inquires if the channel is managed as input. | |
159 * | |
160 * @param channel the channel which is inquired. | |
161 * @return true if the channel is managed as input, false otherwise | |
162 */ | |
163 bool isInput(unsigned int channel){ | |
164 return (bool)((1 << channel) & modeInput); | |
165 } | |
166 | |
167 /** | |
168 * Inquires if the channel is managed as output. | |
169 * | |
170 * @param channel the channel which is inquired. | |
171 * @return true if the channel is managed as output, false otherwise | |
172 */ | |
173 bool isOutput(unsigned int channel){ | |
174 return (bool)((1 << channel) & modeOutput); | |
175 } | |
176 | |
177 /** | |
178 * Sets the output value for a channel. | |
179 * | |
180 * @param channel the channel to set. | |
181 * @param value the value to set. | |
182 */ | |
183 void setValue(unsigned int channel, bool value){ | |
184 if(value == 0){ | |
185 clearDataOut = setBit(clearDataOut, channel); | |
186 setDataOut = clearBit(setDataOut, channel); | |
187 } else { | |
188 setDataOut = setBit(setDataOut, channel); | |
189 clearDataOut = clearBit(clearDataOut, channel); | |
190 } | |
191 } | |
192 | |
193 /** | |
194 * Stops managing a channel. | |
195 * | |
196 * @param channel the channel number | |
197 */ | |
198 void unmanage(unsigned int channel){ | |
199 messageRate = clearBit(messageRate, channel); | |
200 signalRate = clearBit(signalRate, channel); | |
201 modeInput = clearBit(modeInput, channel); | |
202 modeOutput = clearBit(modeOutput, channel); | |
203 clearDataOut = clearBit(clearDataOut, channel); | |
204 setDataOut = clearBit(setDataOut, channel); | |
205 } | |
206 | |
207 /** | |
208 * Manages a channel. | |
209 * | |
210 * Starts managing a channel with given direction and rate. | |
211 * It can be called repeatedly on a given channel to change | |
212 * direction and/or rate. | |
213 * | |
214 * @param channel the channel to manage. | |
215 * @param direction | |
216 */ | |
217 void manage(unsigned int channel, bool direction, bool isMessageRate){ | |
218 // direction is expected to be one of INPUT or OUTPUT | |
219 messageRate = changeBit(messageRate, channel, isMessageRate); | |
220 signalRate = changeBit(signalRate, channel, !isMessageRate); | |
221 if(direction == OUTPUT){ | |
222 modeOutput = setBit(modeOutput, channel); | |
223 modeInput = clearBit(modeInput, channel); | |
224 } else { // direction == INPUT | |
225 modeInput = setBit(modeInput, channel); | |
226 modeOutput = clearBit(modeOutput, channel); | |
227 } | |
228 rt_printf("Bela digital: channel %d is set as %s at %s rate\n", channel, | |
229 isInput(channel) ? "input" : "output", isSignalRate(channel) ? "signal" : "message"); | |
230 } | |
231 | |
232 virtual ~DigitalChannelManager(); | |
233 private: | |
234 bool callbackEnabled; | |
235 void* callbackArg; | |
236 void* callbackArguments[16]; | |
237 void (*stateChangedCallback)(bool value, unsigned int delay, void* arg); | |
238 uint32_t clearDataOut; | |
239 uint32_t setDataOut; | |
240 uint16_t modeOutput; | |
241 uint16_t modeInput; | |
242 uint16_t messageRate; | |
243 uint16_t signalRate; | |
244 }; | |
245 | |
246 #endif /* DIGITALCHANNELMANAGER_H_ */ |