Mercurial > hg > beaglert
changeset 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 | bec5d43e4e7a |
children | bad8a536c157 |
files | core/DigitalChannelManager.cpp examples/basic_libpd/render.cpp include/DigitalChannelManager.h |
diffstat | 3 files changed, 276 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/DigitalChannelManager.cpp Wed Jun 08 21:11:36 2016 +0100 @@ -0,0 +1,18 @@ +/* + * DigitalStream.cpp + * + * Created on: 7 Jun 2016 + * Author: giulio + */ + +#include <DigitalChannelManager.h> + +DigitalChannelManager::DigitalChannelManager() { + // TODO Auto-generated constructor stub + +} + +DigitalChannelManager::~DigitalChannelManager() { + // TODO Auto-generated destructor stub +} +
--- a/examples/basic_libpd/render.cpp Wed Jun 08 19:44:21 2016 +0100 +++ b/examples/basic_libpd/render.cpp Wed Jun 08 21:11:36 2016 +0100 @@ -63,26 +63,27 @@ if(strcmp(source, "bela_setDigital") == 0){ // symbol is the direction, argv[0] is the channel, argv[1] (optional) // is signal(\"sig\" or \"~\") or message(\"mess\", default) rate - bool error = false; bool isMessageRate = true; // defaults to message rate - bool direction; + bool direction = 0; // initialize it just to avoid the compiler's warning + bool disable = false; if(strcmp(symbol, "in") == 0){ direction = INPUT; } else if(strcmp(symbol, "out") == 0){ direction = OUTPUT; + } else if(strcmp(symbol, "disable") == 0){ + disable = true; } else { - error = true; + return; } if(argc == 0){ - error = true; + return; } else if (libpd_is_float(&argv[0]) == false){ - error = true; - } - if(error == true){ - rt_printf("bela_setDigital requires at least [direction channel(\n"); return; } int channel = libpd_get_float(&argv[0]) - LIBPD_DIGITAL_OFFSET; + if(disable == true){ + dcm.unmanage(channel); + } if(argc >= 2){ t_atom* a = &argv[1]; if(libpd_is_symbol(a)){ @@ -92,7 +93,7 @@ } } } - dcm.setPinMode(channel, direction, isMessageRate); + dcm.manage(channel, direction, isMessageRate); } } @@ -111,7 +112,7 @@ unsigned int channel = receiver - 11; // go back to the actual Bela digital channel number if(channel >= 0 && channel < 16){ //16 is the hardcoded value for the number of digital channels //TODO: here we should check if this channel has been registered as message-rate output - dcm.setOutput(channel, value); + dcm.setValue(channel, value); // rt_printf("clear 0x%x set 0x%x\n", clearDataOut, setDataOut); } } @@ -372,6 +373,7 @@ audioWrite(context, audioFrameBase + j, k, *p1); } } + //analog if(context->analogChannels == 8){ for (j = 0, p0 = gOutBuf; j < gLibpdBlockSize; j += 2, p0 += 2) { //write every two frames
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/DigitalChannelManager.h Wed Jun 08 21:11:36 2016 +0100 @@ -0,0 +1,246 @@ +/* + * DigitalStream.h + * + * Created on: 7 Jun 2016 + * Author: giulio + */ + +#ifndef DIGITALCHANNELMANAGER_H_ +#define DIGITALCHANNELMANAGER_H_ +#include <Bela.h> + +/** + * This class manages the digital channels. + * + * Each channel can be set as either signal or message rate. + * When set as message rate: + * inputs are parsed when calling processInput() and a callback + * is invoked when they change state, outputs are set via calls to setValue() and then written + * to the output array when calling processOutput(). + * + * When set at signal rate: + * the DigitalChannelManager only sets the pin direction. + * + * Throughout the class we keep track of message/signal rate + * and input/output in separate variables, so that we + * always know if a channel is managed by the DigitalChannelManager + * or not. This way, managed and unmanaged channels can be freely mixed in the code. + * + * For the reasons above, isSignalRate(channel) is not the same as !isMessageRate(channel) + * and isInput(channel) is not the same as !isOutput(channel) + * + */ + +class DigitalChannelManager { +public: + DigitalChannelManager(); + + /** + * Set the callback. + * + * The callback will be called when one of the managed message-rate input bits + * changes state. The callback's signature is + * void (*stateChangedCallback)(bool value, unsigned int delay, void* arg) + * where \c value is the new value of the channel, \c delay is the sample in the most + * recent block when the status changed, and \c arg is an additional argument passed + * to the callback, which can be set for each channel using setCallbackArgument() + * + */ + + void setCallback(void (*newCallback)(bool, unsigned int, void*)){ + stateChangedCallback = newCallback; + if(newCallback != NULL){ + callbackEnabled = true; + } else { + callbackEnabled = false; + } + }; + + /** + * Sets the argument for the callback. + * + * Typically an argument will allow the callback to identify the channel + * that changed state. + * + * @param channel is the channel for which the argument is set + * @param arg is the argument that will be passed to the callback for that channel + */ + void setCallbackArgument(unsigned int channel, void* arg){ + callbackArguments[channel] = arg; + } + + /** Process the input signals. + * + * Parses the input array and looks for state changes in the bits + * managed as message-rate inputs and invokes the + * appropriate callbacks. + * + * @param the array of input values + * @length the length of the array + * + */ + void processInput(uint32_t* array, unsigned int length){ + if(callbackEnabled == false){ + return; + } + // DIGITAL_FORMAT_ASSUMPTION + static uint16_t lastDigitalInputValues = 0; + for (unsigned int frame = 0; frame < length; ++frame) { + uint32_t inWord = array[frame]; + uint16_t direction = inWord & 0Xffff; + uint16_t inputValues = (inWord >> 16); + // note: even though INPUT == 0 and OUTPUT == 0, this is actually reversed in the binary word, + // so it actually is 1 for input and 0 for output + + // mask out outputValues from the half-word by setting them to zero + // if a bit of direction is 1, then it is an input. + // ANDing this with the inputValues gets rid of the output values + inputValues &= direction; + uint16_t changed = inputValues ^ lastDigitalInputValues; + //mask out channels that are not set at message rate + changed &= messageRate; + if(changed){ +// rt_printf("changed: 0x%x, messageRate: 0x%x, ANDed: 0x%x\n", changed, messageRate, changed&messageRate); + for(int n = 0; n < 16; ++n){ + if(changed & (1 << n)){ //if state for this channel has changed, invoke the callback + stateChangedCallback(inputValues & (1 << n), frame, callbackArguments[n]); + } + } + } + lastDigitalInputValues = inputValues; + } + } + + /** Process the output signals. + * + * Processes the output array and appropriately sets the + * bits managed as message-rate outputs. + * Bits marked as input and unmanaged bits are left alone. + * + * It also updates the channel directions. + * + * @param the array of input values + * @length the length of the array + * + */ + void processOutput(uint32_t* array, unsigned int length){ + uint32_t orWord = ((setDataOut << 16) | modeInput); + uint32_t andWord = ~((clearDataOut << 16) | modeOutput); + uint32_t outWord; + for (unsigned int frame = 0; frame < length; ++frame) { + outWord = array[frame]; + outWord = outWord | orWord; + outWord = outWord & andWord; + array[frame] = outWord; + } + } + + /** + * Inquires if the channel is managed as signal-rate. + * + * @param channel the channel which is inquired. + */ + bool isSignalRate(unsigned int channel){ + return (bool)((1 << channel) & signalRate); + } + + /** + * Inquires if the channel is managed as message-rate. + * + * @param channel the channel which is inquired. + * @return true if the channel is managed at message-rate, false otherwise + */ + bool isMessageRate(unsigned int channel){ + return (bool)((1 << channel) & messageRate); + } + + /** + * Inquires if the channel is managed as input. + * + * @param channel the channel which is inquired. + * @return true if the channel is managed as input, false otherwise + */ + bool isInput(unsigned int channel){ + return (bool)((1 << channel) & modeInput); + } + + /** + * Inquires if the channel is managed as output. + * + * @param channel the channel which is inquired. + * @return true if the channel is managed as output, false otherwise + */ + bool isOutput(unsigned int channel){ + return (bool)((1 << channel) & modeOutput); + } + + /** + * Sets the output value for a channel. + * + * @param channel the channel to set. + * @param value the value to set. + */ + void setValue(unsigned int channel, bool value){ + if(value == 0){ + clearDataOut = setBit(clearDataOut, channel); + setDataOut = clearBit(setDataOut, channel); + } else { + setDataOut = setBit(setDataOut, channel); + clearDataOut = clearBit(clearDataOut, channel); + } + } + + /** + * Stops managing a channel. + * + * @param channel the channel number + */ + void unmanage(unsigned int channel){ + messageRate = clearBit(messageRate, channel); + signalRate = clearBit(signalRate, channel); + modeInput = clearBit(modeInput, channel); + modeOutput = clearBit(modeOutput, channel); + clearDataOut = clearBit(clearDataOut, channel); + setDataOut = clearBit(setDataOut, channel); + } + + /** + * Manages a channel. + * + * Starts managing a channel with given direction and rate. + * It can be called repeatedly on a given channel to change + * direction and/or rate. + * + * @param channel the channel to manage. + * @param direction + */ + void manage(unsigned int channel, bool direction, bool isMessageRate){ + // direction is expected to be one of INPUT or OUTPUT + messageRate = changeBit(messageRate, channel, isMessageRate); + signalRate = changeBit(signalRate, channel, !isMessageRate); + if(direction == OUTPUT){ + modeOutput = setBit(modeOutput, channel); + modeInput = clearBit(modeInput, channel); + } else { // direction == INPUT + modeInput = setBit(modeInput, channel); + modeOutput = clearBit(modeOutput, channel); + } + rt_printf("Bela digital: channel %d is set as %s at %s rate\n", channel, + isInput(channel) ? "input" : "output", isSignalRate(channel) ? "signal" : "message"); + } + + virtual ~DigitalChannelManager(); +private: + bool callbackEnabled; + void* callbackArg; + void* callbackArguments[16]; + void (*stateChangedCallback)(bool value, unsigned int delay, void* arg); + uint32_t clearDataOut; + uint32_t setDataOut; + uint16_t modeOutput; + uint16_t modeInput; + uint16_t messageRate; + uint16_t signalRate; +}; + +#endif /* DIGITALCHANNELMANAGER_H_ */