giuliomoro@354: /* giuliomoro@354: * DigitalStream.h giuliomoro@354: * giuliomoro@354: * Created on: 7 Jun 2016 giuliomoro@354: * Author: giulio giuliomoro@354: */ giuliomoro@354: giuliomoro@354: #ifndef DIGITALCHANNELMANAGER_H_ giuliomoro@354: #define DIGITALCHANNELMANAGER_H_ giuliomoro@354: #include giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * This class manages the digital channels. giuliomoro@354: * giuliomoro@354: * Each channel can be set as either signal or message rate. giuliomoro@354: * When set as message rate: giuliomoro@354: * inputs are parsed when calling processInput() and a callback giuliomoro@354: * is invoked when they change state, outputs are set via calls to setValue() and then written giuliomoro@354: * to the output array when calling processOutput(). giuliomoro@354: * giuliomoro@354: * When set at signal rate: giuliomoro@354: * the DigitalChannelManager only sets the pin direction. giuliomoro@354: * giuliomoro@354: * Throughout the class we keep track of message/signal rate giuliomoro@354: * and input/output in separate variables, so that we giuliomoro@354: * always know if a channel is managed by the DigitalChannelManager giuliomoro@354: * or not. This way, managed and unmanaged channels can be freely mixed in the code. giuliomoro@354: * giuliomoro@354: * For the reasons above, isSignalRate(channel) is not the same as !isMessageRate(channel) giuliomoro@354: * and isInput(channel) is not the same as !isOutput(channel) giuliomoro@354: * giuliomoro@354: */ giuliomoro@354: giuliomoro@354: class DigitalChannelManager { giuliomoro@354: public: giuliomoro@354: DigitalChannelManager(); giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Set the callback. giuliomoro@354: * giuliomoro@354: * The callback will be called when one of the managed message-rate input bits giuliomoro@354: * changes state. The callback's signature is giuliomoro@354: * void (*stateChangedCallback)(bool value, unsigned int delay, void* arg) giuliomoro@354: * where \c value is the new value of the channel, \c delay is the sample in the most giuliomoro@354: * recent block when the status changed, and \c arg is an additional argument passed giuliomoro@354: * to the callback, which can be set for each channel using setCallbackArgument() giuliomoro@354: * giuliomoro@354: */ giuliomoro@354: giuliomoro@354: void setCallback(void (*newCallback)(bool, unsigned int, void*)){ giuliomoro@354: stateChangedCallback = newCallback; giuliomoro@354: if(newCallback != NULL){ giuliomoro@354: callbackEnabled = true; giuliomoro@354: } else { giuliomoro@354: callbackEnabled = false; giuliomoro@354: } giuliomoro@354: }; giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Sets the argument for the callback. giuliomoro@354: * giuliomoro@354: * Typically an argument will allow the callback to identify the channel giuliomoro@354: * that changed state. giuliomoro@354: * giuliomoro@354: * @param channel is the channel for which the argument is set giuliomoro@354: * @param arg is the argument that will be passed to the callback for that channel giuliomoro@354: */ giuliomoro@354: void setCallbackArgument(unsigned int channel, void* arg){ giuliomoro@354: callbackArguments[channel] = arg; giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** Process the input signals. giuliomoro@354: * giuliomoro@354: * Parses the input array and looks for state changes in the bits giuliomoro@354: * managed as message-rate inputs and invokes the giuliomoro@354: * appropriate callbacks. giuliomoro@354: * giuliomoro@361: * @param array the array of input values giuliomoro@361: * @param length the length of the array giuliomoro@354: * giuliomoro@354: */ giuliomoro@354: void processInput(uint32_t* array, unsigned int length){ giuliomoro@354: if(callbackEnabled == false){ giuliomoro@354: return; giuliomoro@354: } giuliomoro@354: // DIGITAL_FORMAT_ASSUMPTION giuliomoro@354: static uint16_t lastDigitalInputValues = 0; giuliomoro@354: for (unsigned int frame = 0; frame < length; ++frame) { giuliomoro@354: uint32_t inWord = array[frame]; giuliomoro@354: uint16_t direction = inWord & 0Xffff; giuliomoro@354: uint16_t inputValues = (inWord >> 16); giuliomoro@354: // note: even though INPUT == 0 and OUTPUT == 0, this is actually reversed in the binary word, giuliomoro@354: // so it actually is 1 for input and 0 for output giuliomoro@354: giuliomoro@354: // mask out outputValues from the half-word by setting them to zero giuliomoro@354: // if a bit of direction is 1, then it is an input. giuliomoro@354: // ANDing this with the inputValues gets rid of the output values giuliomoro@354: inputValues &= direction; giuliomoro@354: uint16_t changed = inputValues ^ lastDigitalInputValues; giuliomoro@354: //mask out channels that are not set at message rate giuliomoro@354: changed &= messageRate; giuliomoro@354: if(changed){ giuliomoro@354: // rt_printf("changed: 0x%x, messageRate: 0x%x, ANDed: 0x%x\n", changed, messageRate, changed&messageRate); giuliomoro@354: for(int n = 0; n < 16; ++n){ giuliomoro@354: if(changed & (1 << n)){ //if state for this channel has changed, invoke the callback giuliomoro@354: stateChangedCallback(inputValues & (1 << n), frame, callbackArguments[n]); giuliomoro@354: } giuliomoro@354: } giuliomoro@354: } giuliomoro@354: lastDigitalInputValues = inputValues; giuliomoro@354: } giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** Process the output signals. giuliomoro@354: * giuliomoro@354: * Processes the output array and appropriately sets the giuliomoro@354: * bits managed as message-rate outputs. giuliomoro@354: * Bits marked as input and unmanaged bits are left alone. giuliomoro@354: * giuliomoro@354: * It also updates the channel directions. giuliomoro@354: * giuliomoro@361: * @param array the array of input values giuliomoro@361: * @param length the length of the array giuliomoro@354: * giuliomoro@354: */ giuliomoro@354: void processOutput(uint32_t* array, unsigned int length){ giuliomoro@354: uint32_t orWord = ((setDataOut << 16) | modeInput); giuliomoro@354: uint32_t andWord = ~((clearDataOut << 16) | modeOutput); giuliomoro@354: uint32_t outWord; giuliomoro@354: for (unsigned int frame = 0; frame < length; ++frame) { giuliomoro@354: outWord = array[frame]; giuliomoro@354: outWord = outWord | orWord; giuliomoro@354: outWord = outWord & andWord; giuliomoro@354: array[frame] = outWord; giuliomoro@354: } giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Inquires if the channel is managed as signal-rate. giuliomoro@354: * giuliomoro@354: * @param channel the channel which is inquired. giuliomoro@354: */ giuliomoro@354: bool isSignalRate(unsigned int channel){ giuliomoro@354: return (bool)((1 << channel) & signalRate); giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Inquires if the channel is managed as message-rate. giuliomoro@354: * giuliomoro@354: * @param channel the channel which is inquired. giuliomoro@354: * @return true if the channel is managed at message-rate, false otherwise giuliomoro@354: */ giuliomoro@354: bool isMessageRate(unsigned int channel){ giuliomoro@354: return (bool)((1 << channel) & messageRate); giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Inquires if the channel is managed as input. giuliomoro@354: * giuliomoro@354: * @param channel the channel which is inquired. giuliomoro@354: * @return true if the channel is managed as input, false otherwise giuliomoro@354: */ giuliomoro@354: bool isInput(unsigned int channel){ giuliomoro@354: return (bool)((1 << channel) & modeInput); giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Inquires if the channel is managed as output. giuliomoro@354: * giuliomoro@354: * @param channel the channel which is inquired. giuliomoro@354: * @return true if the channel is managed as output, false otherwise giuliomoro@354: */ giuliomoro@354: bool isOutput(unsigned int channel){ giuliomoro@354: return (bool)((1 << channel) & modeOutput); giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Sets the output value for a channel. giuliomoro@354: * giuliomoro@354: * @param channel the channel to set. giuliomoro@354: * @param value the value to set. giuliomoro@354: */ giuliomoro@354: void setValue(unsigned int channel, bool value){ giuliomoro@354: if(value == 0){ giuliomoro@354: clearDataOut = setBit(clearDataOut, channel); giuliomoro@354: setDataOut = clearBit(setDataOut, channel); giuliomoro@354: } else { giuliomoro@354: setDataOut = setBit(setDataOut, channel); giuliomoro@354: clearDataOut = clearBit(clearDataOut, channel); giuliomoro@354: } giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Stops managing a channel. giuliomoro@354: * giuliomoro@354: * @param channel the channel number giuliomoro@354: */ giuliomoro@354: void unmanage(unsigned int channel){ giuliomoro@354: messageRate = clearBit(messageRate, channel); giuliomoro@354: signalRate = clearBit(signalRate, channel); giuliomoro@354: modeInput = clearBit(modeInput, channel); giuliomoro@354: modeOutput = clearBit(modeOutput, channel); giuliomoro@354: clearDataOut = clearBit(clearDataOut, channel); giuliomoro@354: setDataOut = clearBit(setDataOut, channel); giuliomoro@354: } giuliomoro@354: giuliomoro@354: /** giuliomoro@354: * Manages a channel. giuliomoro@354: * giuliomoro@354: * Starts managing a channel with given direction and rate. giuliomoro@354: * It can be called repeatedly on a given channel to change giuliomoro@354: * direction and/or rate. giuliomoro@354: * giuliomoro@354: * @param channel the channel to manage. giuliomoro@354: * @param direction giuliomoro@354: */ giuliomoro@354: void manage(unsigned int channel, bool direction, bool isMessageRate){ giuliomoro@354: // direction is expected to be one of INPUT or OUTPUT giuliomoro@354: messageRate = changeBit(messageRate, channel, isMessageRate); giuliomoro@354: signalRate = changeBit(signalRate, channel, !isMessageRate); giuliomoro@354: if(direction == OUTPUT){ giuliomoro@354: modeOutput = setBit(modeOutput, channel); giuliomoro@354: modeInput = clearBit(modeInput, channel); giuliomoro@354: } else { // direction == INPUT giuliomoro@354: modeInput = setBit(modeInput, channel); giuliomoro@354: modeOutput = clearBit(modeOutput, channel); giuliomoro@354: } giuliomoro@354: rt_printf("Bela digital: channel %d is set as %s at %s rate\n", channel, giuliomoro@354: isInput(channel) ? "input" : "output", isSignalRate(channel) ? "signal" : "message"); giuliomoro@354: } giuliomoro@354: giuliomoro@354: virtual ~DigitalChannelManager(); giuliomoro@354: private: giuliomoro@354: bool callbackEnabled; giuliomoro@354: void* callbackArg; giuliomoro@354: void* callbackArguments[16]; giuliomoro@354: void (*stateChangedCallback)(bool value, unsigned int delay, void* arg); giuliomoro@354: uint32_t clearDataOut; giuliomoro@354: uint32_t setDataOut; giuliomoro@354: uint16_t modeOutput; giuliomoro@354: uint16_t modeInput; giuliomoro@354: uint16_t messageRate; giuliomoro@354: uint16_t signalRate; giuliomoro@354: }; giuliomoro@354: giuliomoro@354: #endif /* DIGITALCHANNELMANAGER_H_ */