Corrected data load, where a full buffer would cause a hang

master
boblark 2 years ago
parent 8767bf4874
commit 9993a0b922
  1. 65
      radioBFSKmodulator_F32.cpp
  2. 36
      radioBFSKmodulator_F32.h

@ -5,64 +5,78 @@
* *
* License: MIT License. Use at your own risk. See corresponding .h file. * 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" #include "radioBFSKmodulator_F32.h"
// 513 values of the sine wave in a float array: // 513 values of the sine wave in a float array:
#include "sinTable512_f32.h" #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) { void RadioBFSKModulator_F32::update(void) {
audio_block_f32_t *blockFSK; audio_block_f32_t *blockFSK;
uint16_t index, i; uint16_t index, i;
float32_t vca; float32_t vca;
float32_t a, b; float32_t a, b;
// uint32_t tt=micros(); // uint32_t tt=micros();
blockFSK = AudioStream_F32::allocate_f32(); // Get the output block blockFSK = AudioStream_F32::allocate_f32(); // Get the output block
if (!blockFSK) return; 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++) for (i=0; i < blockFSK->length; i++)
{ {
samplePerBitCount++;
// Each data bit is an integer number of sample periods // 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 if(bitSendCount < numBits) // Still sending a word, get next bit
{ {
vc = (uint16_t)(currentWord & 1); vc = (uint16_t)(currentWord & 1); // Send 0 or 1
currentWord = currentWord >> 1; currentWord = currentWord >> 1; // Next bit position
bitSendCount++; bitSendCount++;
samplePerBitCount = 0;
} }
else if((indexIn - indexOut) > 0) // Is there another word ready? else // End of word, get another if possible
{
if(stateBuffer != DATA_BUFFER_EMPTY)
{ {
atIdle = false;
indexOut++; // Just keeps on going, not circular indexOut++; // Just keeps on going, not circular
checkBuffer();
currentWord = dataBuffer[indexOut&indexMask]; currentWord = dataBuffer[indexOut&indexMask];
// Serial.print(indexIn);
// Serial.print(" In Out ");
// Serial.println(indexOut);
vc = (uint16_t)(currentWord & 1); // Bit to send next vc = (uint16_t)(currentWord & 1); // Bit to send next
bitSendCount = 1U; // Count how many bits have been sent bitSendCount = 1U; // Count how many bits have been sent
currentWord = currentWord >> 1; currentWord = currentWord >> 1;
samplePerBitCount = 0;
} }
else // No bits are available else // No word available
{ {
atIdle = true;
vc = 1; //Idle at logic 1 (Make programmable?) vc = 1; //Idle at logic 1 (Make programmable?)
samplePerBitCount = samplesPerDataBit + 1; // Force revisit
}
} }
} // end, get another word
} // end, bit transition time
if(FIRcoeff==NULL) // No LPF being used if(FIRcoeff==NULL) // No LPF being used
vca = (float32_t)vc; vca = (float32_t)vc;
@ -83,6 +97,8 @@ void RadioBFSKModulator_F32::update(void) {
vca += FIRcoeff[k]*FIRdata[ii]; vca += FIRcoeff[k]*FIRdata[ii];
} }
} }
// Modulate baseband vca voltage to sine wave frequency (VCO)
// pre-multiply phaseIncrement[0]=kp*freq[0] and deltaPhase=kp*deltaFreq // pre-multiply phaseIncrement[0]=kp*freq[0] and deltaPhase=kp*deltaFreq
currentPhase += (phaseIncrement[0] + vca*deltaPhase); currentPhase += (phaseIncrement[0] + vca*deltaPhase);
if (currentPhase > 512.0f) currentPhase -= 512.0f; if (currentPhase > 512.0f) currentPhase -= 512.0f;
@ -99,3 +115,4 @@ void RadioBFSKModulator_F32::update(void) {
AudioStream_F32::release (blockFSK); AudioStream_F32::release (blockFSK);
// Serial.print(" "); Serial.println(micros()-tt); // Serial.print(" "); Serial.println(micros()-tt);
} }

@ -69,6 +69,9 @@ Frequency deviation: ±30 Hz
* The update() uses about 13 microseconds for 128 points with no LPF * The update() uses about 13 microseconds for 128 points with no LPF
* on the control signal. The LPF adds roughly 3 icroseconds per * on the control signal. The LPF adds roughly 3 icroseconds per
* FIR coefficient being used. * 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 /* Here is an Octave/Matlab .m file to design the Gaussian LP FIR filter
@ -152,25 +155,37 @@ public:
block_size = settings.audio_block_samples; 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? // As viewed from the INO, does the bufffer have space?
bool bufferHasSpace(void) { bool bufferHasSpace(void) {
if((64LL - indexIn + indexOut) <= 0LL) { //Serial.print(indexIn); checkBuffer();
//Serial.print(" NR1 ");Serial.println(indexOut); delay(4); if(stateBuffer == DATA_BUFFER_FULL)
return false; } // No room for more return false;
else
return true; return true;
} }
int16_t getBufferSpace(void) {
return 64-checkBuffer();
}
// As viewed from the INO, put a data word into the buffer to send. // As viewed from the INO, put a data word into the buffer to send.
// Returns true if successful. // Returns true if successful.
bool sendData(uint32_t data) { bool sendData(uint32_t data) {
int64_t space = 64LL - indexIn + indexOut; checkBuffer();
if(space <= 0LL) { // No room if(stateBuffer == DATA_BUFFER_FULL)
return false; return false;
} else
{
indexIn++; indexIn++;
dataBuffer[indexIn & indexMask] = data; dataBuffer[indexIn & indexMask] = data;
checkBuffer();
return true; return true;
} }
}
void bufferClear(void) { void bufferClear(void) {
indexIn = 0LL; indexIn = 0LL;
@ -225,8 +240,13 @@ public:
samplesPerDataBit = (uint32_t)(0.5 + sample_rate_Hz/bitRate); samplesPerDataBit = (uint32_t)(0.5 + sample_rate_Hz/bitRate);
} }
int16_t checkBuffer(void);
virtual void update(void); virtual void update(void);
#define DATA_BUFFER_EMPTY 0
#define DATA_BUFFER_PART 1
#define DATA_BUFFER_FULL 2
private: private:
float32_t sample_rate_Hz = AUDIO_SAMPLE_RATE_EXACT; float32_t sample_rate_Hz = AUDIO_SAMPLE_RATE_EXACT;
uint16_t block_size = 128; uint16_t block_size = 128;
@ -241,9 +261,6 @@ private:
uint32_t currentWord = 0UL; uint32_t currentWord = 0UL;
uint16_t numBits = 10; uint16_t numBits = 10;
uint16_t bitSendCount = 0; 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?? uint32_t dataBuffer[64]; // Make 64 a define??
// By using a 64-bit index we never need to wrap around. // 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 indexIn = 0ULL; // Next word to be entered to buffer
int64_t indexOut = 0ULL; // Next word to be sent int64_t indexOut = 0ULL; // Next word to be sent
int64_t indexMask = 0X003F; // Goes with 64 int64_t indexMask = 0X003F; // Goes with 64
uint16_t stateBuffer = DATA_BUFFER_EMPTY;
uint16_t vc = 0; uint16_t vc = 0;
uint32_t samplePerBitCount = 0; uint32_t samplePerBitCount = 0;

Loading…
Cancel
Save