annotate include/DigitalChannelManager.h @ 496:eb237b131ec7 prerelease

Tested and fixed midi glitches heavy
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 21 Jun 2016 20:00:12 +0100
parents 838a4a4a8580
children
rev   line source
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_ */