From 9993a0b922e01e8509c4c48b4d2e74f5ec0806c1 Mon Sep 17 00:00:00 2001 From: boblark Date: Mon, 3 Apr 2023 17:33:42 -0700 Subject: [PATCH] Corrected data load, where a full buffer would cause a hang --- radioBFSKmodulator_F32.cpp | 85 +++++++++++++++++++++++--------------- radioBFSKmodulator_F32.h | 46 ++++++++++++++------- 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/radioBFSKmodulator_F32.cpp b/radioBFSKmodulator_F32.cpp index c4210af..e6ed748 100644 --- a/radioBFSKmodulator_F32.cpp +++ b/radioBFSKmodulator_F32.cpp @@ -5,64 +5,78 @@ * * License: MIT License. Use at your own risk. See corresponding .h file. * + * 2 April 2023 -Corrected to handle outputs from a full buffer. RSL + * Added int16_t getBufferSpace(). RSL */ #include "radioBFSKmodulator_F32.h" // 513 values of the sine wave in a float array: #include "sinTable512_f32.h" +// 64 entry send buffer check. Sets stateBuffer +// Returns the number of un-transmitted characters. +int16_t RadioBFSKModulator_F32::checkBuffer(void) { + int64_t deltaIndex = indexIn - indexOut; + + if(deltaIndex==0LL) + stateBuffer = DATA_BUFFER_EMPTY; + else if(deltaIndex==64LL) + stateBuffer = DATA_BUFFER_FULL; + else + stateBuffer = DATA_BUFFER_PART; + + if(deltaIndex<0LL || deltaIndex>64LL) // Should never happen + { + Serial.print("ERROR in Buffer; deltaIndex = "); + Serial.println(deltaIndex); + } + return (int16_t)deltaIndex; + } + void RadioBFSKModulator_F32::update(void) { audio_block_f32_t *blockFSK; uint16_t index, i; float32_t vca; float32_t a, b; - // uint32_t tt=micros(); blockFSK = AudioStream_F32::allocate_f32(); // Get the output block if (!blockFSK) return; - // Note - If buffer is dry, there is a delay of up to 3 mSec. Should be OK - - // Note: indexIn and indexOut will not change during this update(), - // as we have the interrupt. - - if(atIdle && (indexIn - indexOut) > 0) // At idle and new buffer entry has arrived - { - atIdle = false; - bitSendCount = numBits + 1; // Force new start - samplePerBitCount = samplesPerDataBit + 1; - } - for (i=0; i < blockFSK->length; i++) { + samplePerBitCount++; // Each data bit is an integer number of sample periods - if(samplePerBitCount >= samplesPerDataBit) // Time for either idle or new bit/word + if(samplePerBitCount >= samplesPerDataBit) // Bit transition time { + samplePerBitCount = 0; // Wait a bit period before checking again if(bitSendCount < numBits) // Still sending a word, get next bit { - vc = (uint16_t)(currentWord & 1); - currentWord = currentWord >> 1; + vc = (uint16_t)(currentWord & 1); // Send 0 or 1 + currentWord = currentWord >> 1; // Next bit position bitSendCount++; - samplePerBitCount = 0; } - else if((indexIn - indexOut) > 0) // Is there another word ready? + else // End of word, get another if possible { - atIdle = false; - indexOut++; // Just keeps on going, not circular - currentWord = dataBuffer[indexOut&indexMask]; - vc = (uint16_t)(currentWord & 1); // Bit to send next - bitSendCount = 1U; // Count how many bits have been sent - currentWord = currentWord >> 1; - samplePerBitCount = 0; - } - else // No bits are available - { - atIdle = true; - vc = 1; //Idle at logic 1 (Make programmable?) - samplePerBitCount = samplesPerDataBit + 1; // Force revisit - } - } + if(stateBuffer != DATA_BUFFER_EMPTY) + { + indexOut++; // Just keeps on going, not circular + checkBuffer(); + currentWord = dataBuffer[indexOut&indexMask]; +// Serial.print(indexIn); +// Serial.print(" In Out "); +// Serial.println(indexOut); + vc = (uint16_t)(currentWord & 1); // Bit to send next + bitSendCount = 1U; // Count how many bits have been sent + currentWord = currentWord >> 1; + } + else // No word available + { + vc = 1; //Idle at logic 1 (Make programmable?) + } + } // end, get another word + } // end, bit transition time + if(FIRcoeff==NULL) // No LPF being used vca = (float32_t)vc; @@ -83,7 +97,9 @@ void RadioBFSKModulator_F32::update(void) { vca += FIRcoeff[k]*FIRdata[ii]; } } - // pre-multiply phaseIncrement[0]=kp*freq[0] and deltaPhase=kp*deltaFreq + + // Modulate baseband vca voltage to sine wave frequency (VCO) + // pre-multiply phaseIncrement[0]=kp*freq[0] and deltaPhase=kp*deltaFreq currentPhase += (phaseIncrement[0] + vca*deltaPhase); if (currentPhase > 512.0f) currentPhase -= 512.0f; index = (uint16_t) currentPhase; @@ -99,3 +115,4 @@ void RadioBFSKModulator_F32::update(void) { AudioStream_F32::release (blockFSK); // Serial.print(" "); Serial.println(micros()-tt); } + diff --git a/radioBFSKmodulator_F32.h b/radioBFSKmodulator_F32.h index 505e5ec..640be11 100644 --- a/radioBFSKmodulator_F32.h +++ b/radioBFSKmodulator_F32.h @@ -69,6 +69,9 @@ Frequency deviation: ±30 Hz * The update() uses about 13 microseconds for 128 points with no LPF * on the control signal. The LPF adds roughly 3 icroseconds per * FIR coefficient being used. + * + * 2 April 2023 -Corrected to handle outputs from full buffer. RSL + * Added int16_t getBufferSpace(). RSL */ /* Here is an Octave/Matlab .m file to design the Gaussian LP FIR filter @@ -152,24 +155,36 @@ public: block_size = settings.audio_block_samples; } +#define DATA_BUFFER_EMPTY 0 +#define DATA_BUFFER_PART 1 +#define DATA_BUFFER_FULL 2 + // As viewed from the INO, does the bufffer have space? bool bufferHasSpace(void) { - if((64LL - indexIn + indexOut) <= 0LL) { //Serial.print(indexIn); - //Serial.print(" NR1 ");Serial.println(indexOut); delay(4); - return false; } // No room for more - return true; + checkBuffer(); + if(stateBuffer == DATA_BUFFER_FULL) + return false; + else + return true; + } + + int16_t getBufferSpace(void) { + return 64-checkBuffer(); } // As viewed from the INO, put a data word into the buffer to send. // Returns true if successful. bool sendData(uint32_t data) { - int64_t space = 64LL - indexIn + indexOut; - if(space <= 0LL) { // No room + checkBuffer(); + if(stateBuffer == DATA_BUFFER_FULL) return false; + else + { + indexIn++; + dataBuffer[indexIn & indexMask] = data; + checkBuffer(); + return true; } - indexIn++; - dataBuffer[indexIn & indexMask] = data; - return true; } void bufferClear(void) { @@ -204,8 +219,8 @@ public: // Low pass filter on frequency control line. Set to NULL to omitfilter. void setLPF(float32_t* _FIRdata, float32_t* _FIRcoeff, uint16_t _numCoeffs) { FIRdata = _FIRdata; - if(_FIRcoeff == NULL || _numCoeffs == 0) - { + if(_FIRcoeff == NULL || _numCoeffs == 0) + { FIRcoeff = NULL; numCoeffs = 0; return; @@ -225,8 +240,13 @@ public: samplesPerDataBit = (uint32_t)(0.5 + sample_rate_Hz/bitRate); } + int16_t checkBuffer(void); virtual void update(void); +#define DATA_BUFFER_EMPTY 0 +#define DATA_BUFFER_PART 1 +#define DATA_BUFFER_FULL 2 + private: float32_t sample_rate_Hz = AUDIO_SAMPLE_RATE_EXACT; uint16_t block_size = 128; @@ -241,9 +261,6 @@ private: uint32_t currentWord = 0UL; uint16_t numBits = 10; uint16_t bitSendCount = 0; - // atIdle means no data is available. But, keep on sending a sine wave - // at the logic 1 frequency. - bool atIdle = true; uint32_t dataBuffer[64]; // Make 64 a define?? // By using a 64-bit index we never need to wrap around. @@ -251,6 +268,7 @@ private: int64_t indexIn = 0ULL; // Next word to be entered to buffer int64_t indexOut = 0ULL; // Next word to be sent int64_t indexMask = 0X003F; // Goes with 64 + uint16_t stateBuffer = DATA_BUFFER_EMPTY; uint16_t vc = 0; uint32_t samplePerBitCount = 0;