Mercurial > hg > beaglert
changeset 272:733006bdbca2 prerelease
Added Scope.h and Scope.cpp
author | Liam Donovan <l.b.donovan@qmul.ac.uk> |
---|---|
date | Tue, 17 May 2016 16:17:48 +0100 |
parents | fb9c28a4676b |
children | 0ee6eebb567a |
files | core/Scope.cpp include/Scope.h |
diffstat | 2 files changed, 368 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/Scope.cpp Tue May 17 16:17:48 2016 +0100 @@ -0,0 +1,282 @@ +/***** Scope.cpp *****/ +#include <Scope.h> + +Scope::Scope():connected(0), triggerPrimed(false), started(false){} + +// static aux task functions +void Scope::triggerTask(void *ptr){ + Scope *instance = (Scope*)ptr; + if (instance->started) + instance->doTrigger(); +} +void Scope::sendBufferTask(void *ptr){ + Scope *instance = (Scope*)ptr; + instance->sendBuffer(); +} + +void Scope::setup(unsigned int _numChannels, float _sampleRate){ + + numChannels = _numChannels; + sampleRate = _sampleRate; + + // setup the OSC server && client + // used for sending / recieving settings + // oscClient has it's send task turned off, as we only need to send one handshake message + oscServer.setup(OSC_RECIEVE_PORT); + oscClient.setup(OSC_SEND_PORT, "127.0.0.1", false); + + // setup the udp socket + // used for sending raw frame data + socket.setServer("127.0.0.1"); + socket.setPort(SCOPE_UDP_PORT); + + // setup the auxiliary tasks + scopeTriggerTask = BeagleRT_createAuxiliaryTask(Scope::triggerTask, BEAGLERT_AUDIO_PRIORITY-2, "scopeTriggerTask", this, true); + scopeSendBufferTask = BeagleRT_createAuxiliaryTask(Scope::sendBufferTask, BEAGLERT_AUDIO_PRIORITY-1, "scopeSendBufferTask", this); + + // send an OSC message to address /scope-setup + // then wait 1 second for a reply on /scope-setup-reply + bool handshakeRecieved = false; + oscClient.sendMessageNow(oscClient.newMessage.to("/scope-setup").add((int)numChannels).add(sampleRate).end()); + oscServer.recieveMessageNow(1000); + while (oscServer.messageWaiting()){ + if (handshakeRecieved){ + parseMessage(oscServer.popMessage()); + } else if (oscServer.popMessage().match("/scope-setup-reply")){ + handshakeRecieved = true; + } + } + + if (handshakeRecieved && connected) + start(); + +} + +void Scope::start(){ + + // resize the buffers + channelWidth = frameWidth * FRAMES_STORED; + buffer.resize(numChannels*channelWidth); + outBuffer.resize(numChannels*frameWidth); + + // reset the pointers + writePointer = 0; + readPointer = 0; + triggerPointer = 0; + + // reset the trigger + triggerPrimed = true; + triggerCollecting = false; + triggerWaiting = false; + triggerCount = 0; + downSampleCount = 1; + autoTriggerCount = 0; + customTriggered = false; + + started = true; +} + +void Scope::stop(){ + started = false; +} + +void Scope::log(float chn1, ...){ + + // check for any recieved OSC messages + while (oscServer.messageWaiting()){ + parseMessage(oscServer.popMessage()); + } + + if (!started) return; + + if (downSampling > 1){ + if (downSampleCount < downSampling){ + downSampleCount++; + return; + } + downSampleCount = 1; + } + + va_list args; + va_start (args, chn1); + + int startingWritePointer = writePointer; + + // save the logged samples into the buffer + buffer[writePointer] = chn1; + + for (int i=1; i<numChannels; i++) { + // iterate over the function arguments, store them in the relevant part of the buffer + // channels are stored sequentially in the buffer i.e [[channel1], [channel2], etc...] + buffer[i*channelWidth + writePointer] = (float)va_arg(args, double); + } + + writePointer = (writePointer+1)%channelWidth; + + // if upSampling > 1, save repeated samples into the buffer + for (int j=1; j<upSampling; j++){ + + buffer[writePointer] = buffer[startingWritePointer]; + + for (int i=1; i<numChannels; i++) { + buffer[i*channelWidth + writePointer] = buffer[i*channelWidth + startingWritePointer]; + } + + writePointer = (writePointer+1)%channelWidth; + + } + + va_end (args); + +} + +bool Scope::trigger(){ + if (triggerMode == 2 && !customTriggered && triggerPrimed && started){ + customTriggerPointer = (writePointer-xOffset+channelWidth)%channelWidth; + customTriggered = true; + return true; + } + return false; +} + +void Scope::scheduleSendBufferTask(){ + BeagleRT_scheduleAuxiliaryTask(scopeSendBufferTask); +} + +bool Scope::triggered(){ + if (triggerMode == 0 || triggerMode == 1){ // normal or auto trigger + return (!triggerDir && buffer[channelWidth*triggerChannel+((readPointer-1+channelWidth)%channelWidth)] < triggerLevel // positive trigger direction + && buffer[channelWidth*triggerChannel+readPointer] >= triggerLevel) || + (triggerDir && buffer[channelWidth*triggerChannel+((readPointer-1+channelWidth)%channelWidth)] > triggerLevel // negative trigger direciton + && buffer[channelWidth*triggerChannel+readPointer] <= triggerLevel); + } else if (triggerMode == 2){ // custom trigger + return (customTriggered && readPointer == customTriggerPointer); + } + return false; +} + +void Scope::doTrigger(){ + // iterate over the samples between the read and write pointers and check for / deal with triggers + while (readPointer != writePointer){ + + // if we are currently listening for a trigger + if (triggerPrimed){ + + // if we crossed the trigger threshold + if (triggered()){ + + // stop listening for a trigger + triggerPrimed = false; + triggerCollecting = true; + + // save the readpointer at the trigger point + triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth; + + triggerCount = frameWidth/2 - xOffset; + autoTriggerCount = 0; + + } else { + // auto triggering + if (triggerMode == 0 && (autoTriggerCount++ > (frameWidth+holdOff))){ + // it's been a whole frameWidth since we've found a trigger, so auto-trigger anyway + triggerPrimed = false; + triggerCollecting = true; + + // save the readpointer at the trigger point + triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth; + + triggerCount = frameWidth/2 - xOffset; + autoTriggerCount = 0; + } + } + + } else if (triggerCollecting){ + + // a trigger has been detected, and we are collecting the second half of the triggered frame + if (--triggerCount > 0){ + + } else { + triggerCollecting = false; + triggerWaiting = true; + triggerCount = frameWidth/2 + holdOffSamples; + + // copy the previous to next frameWidth/2 samples into the outBuffer + int startptr = (triggerPointer-frameWidth/2 + channelWidth)%channelWidth; + int endptr = (triggerPointer+frameWidth/2 + channelWidth)%channelWidth; + + if (endptr > startptr){ + for (int i=0; i<numChannels; i++){ + std::copy(&buffer[channelWidth*i+startptr], &buffer[channelWidth*i+endptr], outBuffer.begin()+(i*frameWidth)); + } + } else { + for (int i=0; i<numChannels; i++){ + std::copy(&buffer[channelWidth*i+startptr], &buffer[channelWidth*(i+1)], outBuffer.begin()+(i*frameWidth)); + std::copy(&buffer[channelWidth*i], &buffer[channelWidth*i+endptr], outBuffer.begin()+((i+1)*frameWidth-endptr)); + } + } + + // the whole frame has been saved in outBuffer, so send it + scheduleSendBufferTask(); + + } + + } else if (triggerWaiting){ + + // a trigger has completed, so wait half a framewidth before looking for another + if (--triggerCount > 0){ + + } else { + triggerWaiting = false; + triggerPrimed = true; + customTriggered = false; + } + + } + + // increment the read pointer + readPointer = (readPointer+1)%channelWidth; + } + +} + +void Scope::sendBuffer(){ + socket.send(&(outBuffer[0]), outBuffer.size()*sizeof(float)); +} + +void Scope::parseMessage(oscpkt::Message msg){ + if (msg.partialMatch("/scope-settings/")){ + int intArg; + float floatArg; + if (msg.match("/scope-settings/connected").popInt32(intArg).isOkNoMoreArgs()){ + if (connected == 0 && intArg == 1){ + start(); + } else if (connected == 1 && intArg == 0){ + stop(); + } + connected = intArg; + } else if (msg.match("/scope-settings/frameWidth").popInt32(intArg).isOkNoMoreArgs()){ + stop(); + frameWidth = intArg; + start(); + } else if (msg.match("/scope-settings/triggerMode").popInt32(intArg).isOkNoMoreArgs()){ + triggerMode = intArg; + } else if (msg.match("/scope-settings/triggerChannel").popInt32(intArg).isOkNoMoreArgs()){ + triggerChannel = intArg; + } else if (msg.match("/scope-settings/triggerDir").popInt32(intArg).isOkNoMoreArgs()){ + triggerDir = intArg; + } else if (msg.match("/scope-settings/triggerLevel").popFloat(floatArg).isOkNoMoreArgs()){ + triggerLevel = floatArg; + } else if (msg.match("/scope-settings/xOffset").popInt32(intArg).isOkNoMoreArgs()){ + xOffset = intArg; + } else if (msg.match("/scope-settings/upSampling").popInt32(intArg).isOkNoMoreArgs()){ + upSampling = intArg; + holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); + } else if (msg.match("/scope-settings/downSampling").popInt32(intArg).isOkNoMoreArgs()){ + downSampling = intArg; + holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); + } else if (msg.match("/scope-settings/holdOff").popFloat(floatArg).isOkNoMoreArgs()){ + holdOff = floatArg; + holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/Scope.h Tue May 17 16:17:48 2016 +0100 @@ -0,0 +1,86 @@ +/***** Scope.h *****/ +#ifndef __Scope_H_INCLUDED__ +#define __Scope_H_INCLUDED__ + +#include <OSCServer.h> +#include <OSCClient.h> +#include <stdarg.h> + +#define OSC_RECIEVE_PORT 8675 +#define OSC_SEND_PORT 8676 +#define SCOPE_UDP_PORT 8677 + +#define FRAMES_STORED 2 + +class Scope{ + public: + Scope(); + + void setup(unsigned int numChannels, float sampleRate); + void log(float chn1, ...); + bool trigger(); + + private: + OSCServer oscServer; + OSCClient oscClient; + UdpClient socket; + + void parseMessage(oscpkt::Message); + void start(); + void stop(); + void doTrigger(); + void triggerNormal(); + void triggerAuto(); + void scheduleSendBufferTask(); + void sendBuffer(); + void customTrigger(); + bool triggered(); + + // settings + int numChannels; + float sampleRate; + int connected; + int frameWidth; + int triggerMode; + int triggerChannel; + int triggerDir; + float triggerLevel; + int xOffset; + int upSampling; + int downSampling; + float holdOff; + + int channelWidth; + int downSampleCount; + int holdOffSamples; + + // buffers + std::vector<float> buffer; + std::vector<float> outBuffer; + + // pointers + int writePointer; + int readPointer; + int triggerPointer; + int customTriggerPointer; + + // trigger status + bool triggerPrimed; + bool triggerCollecting; + bool triggerWaiting; + bool triggering; + int triggerCount; + int autoTriggerCount; + bool started; + bool customTriggered; + + // aux tasks + AuxiliaryTask scopeTriggerTask; + static void triggerTask(void*); + + AuxiliaryTask scopeSendBufferTask; + static void sendBufferTask(void*); + +}; + +#endif \ No newline at end of file