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