|
|
|
/*
|
|
|
|
* radioBFSKmodulator_F32.cpp
|
|
|
|
*
|
|
|
|
* Created: Bob Larkin 17 March 2022
|
|
|
|
*
|
|
|
|
* License: MIT License. Use at your own risk. See corresponding .h file.
|
|
|
|
*
|
|
|
|
* 2 April 2023 -Corrected to handle outputs from 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;
|
|
|
|
|
|
|
|
for (i=0; i < blockFSK->length; i++)
|
|
|
|
{
|
|
|
|
samplePerBitCount++;
|
|
|
|
// Each data bit is an integer number of sample periods
|
|
|
|
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); // Send 0 or 1
|
|
|
|
currentWord = currentWord >> 1; // Next bit position
|
|
|
|
bitSendCount++;
|
|
|
|
}
|
|
|
|
else // End of word, get another if possible
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Put latest data point intoFIR LPF buffer
|
|
|
|
indexFIRlatest++;
|
|
|
|
FIRdata[indexFIRlatest & indexFIRMask] = (float32_t)vc; // Add to buffer
|
|
|
|
// Optional FIR LPF
|
|
|
|
vca = 0.0f;
|
|
|
|
int16_t iiBase16 = (int16_t)(indexFIRlatest & indexFIRMask);
|
|
|
|
int16_t iiSize = (int16_t)(indexFIRMask + 1ULL);
|
|
|
|
for(int16_t k=0; k<numCoeffs; k++)
|
|
|
|
{
|
|
|
|
int16_t ii = iiBase16 - k;
|
|
|
|
if(ii < 0)
|
|
|
|
ii += iiSize;
|
|
|
|
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
|
|
|
|
currentPhase += (phaseIncrement[0] + vca*deltaPhase);
|
|
|
|
if (currentPhase > 512.0f) currentPhase -= 512.0f;
|
|
|
|
index = (uint16_t) currentPhase;
|
|
|
|
float32_t deltaPhase = currentPhase - (float32_t)index;
|
|
|
|
/* Read two nearest values of input value from the sin table */
|
|
|
|
a = sinTable512_f32[index];
|
|
|
|
b = sinTable512_f32[index+1];
|
|
|
|
blockFSK->data[i] = magnitude*(a+(b-a)*deltaPhase); // Linear interpolation
|
|
|
|
samplePerBitCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioStream_F32::transmit(blockFSK);
|
|
|
|
AudioStream_F32::release (blockFSK);
|
|
|
|
// Serial.print(" "); Serial.println(micros()-tt);
|
|
|
|
}
|