2023-09-04 19:06:44 +01:00
//
// OFDM Module for ARDOP
//
/*
Thoughts on OFDM
We have lots ( ? 43 ) carriers , so requiring all to be good is unlikely to succeed
If we ack each carrier separately we need some form of block number , so we can infill bits of data that were missed .
Always sending first block on first carrier seems a bad idea ( but look at redundancy ideas below )
We could send the same data ( with same block number ) on multiple carriers for resilience
We need a ack frame with one bit per carrier ( ? 6 bytes ) which is about 1 sec with 50 baud ( do we need fec or just crc ? ? ) .
Could send ACK at 100 baud , shortening it a bit , but is overall throughput increace worth it ?
Using one byte block number but limit to 0 - 127. Window is 10160 in 16 QAM or 12700 for 32 QAM
unless we use a different block length for each mode . Takes 10 % of 2F SK throughput .
Receiver must be able to hold window of frames ( may be a problem with Teensy )
Must handle missed ack . ? base next ack on combination of repeats ?
Should we wait to pass to host till next seq frame received or all received ok ?
Should we have multiple frame types for each mod mode , or add a frame type to carrier ?
Ideally would like 2 , 4 , 8 PSK , 16 , 32 QAM . Too many if we stick with ARDOP2 frame structure , so need frame type
Frame type has to be sent in fixed mode ( not same as data ) we need 2 or 3 bits . With 2F SK that is about 60 mS .
Need to validate . If we use same type for all carriers ( any good reason not to ? ) we can decode type byte on all
frames and compare . Very unlikely to choose wrong one , even if some are different . Could even try more than one (
may be a problem with Teensy ) .
Could use combination of redundancy and mode to give very wide speed ( and hopefully resilience ) ratio , but gear
shifting may be a nightmare .
Is reducing carriers and therefore increasing power per carrier better than massive redundacy with lots of carriers ?
Would dividing single carrier into multiple RS blocks be beneficial ? Adds 3 byte overhead per block ( Len and CRC )
if done with slow carriers would limit window size , so may need different block size per mode , which makes reassembly tricky
For a block of 4 - 5 secs we get
16 OFDM 80 bytes / carrier , 3440 bytes per frame , approx 4600 BPS Net
8 OFDM 60 bytes / carrier , 2580 bytes per frame , approx 3440 BPS Net
4 OFDM 40 bytes / carrier , 1720 bytes per frame , approx 2300 BPS Net
2 OFDM 20 bytes / carrier , 860 bytes per frame , approx 1150 BPS Net
For Comparison 16 QAM .2500 .100
120 bytes / carrier , 1200 bytes per frame , approx 2225 BPS Net
*/
# ifdef WIN32
# define _CRT_SECURE_NO_DEPRECATE
# include <windows.h>
# else
# define SOCKET int
# include <unistd.h>
# define closesocket close
# endif
# include <math.h>
# include "ARDOPC.h"
# pragma warning(disable : 4244) // Code does lots of float to int
int OFDMMode ; // OFDM can use various modulation modes and redundancy levels
int LastSentOFDMMode ; // For retries
int LastSentOFDMType ; // For retries
int SavedOFDMMode = - 1 ; // used if we switch to a more robust mode cos we don't have much to send
int SavedFrameType ;
extern UCHAR bytCurrentFrameType ;
int RXOFDMMode = 0 ;
const char OFDMModes [ 8 ] [ 6 ] = { " PSK2 " , " PSK4 " , " PSK8 " , " QAM16 " , " PSK16 " , " QAM32 " , " PSK4S " , " Undef " } ;
int OFDMFrameLen [ 8 ] = { 19 , 40 , 57 , 80 , 80 } ; // Bytes per carrier for each submode
int OFDMCarriersReceived [ 8 ] = { 0 } ;
int OFDMCarriersDecoded [ 8 ] = { 0 } ;
int OFDMCarriersNaked [ 8 ] = { 0 } ;
int OFDMCarriersAcked [ 8 ] = { 0 } ;
// Functions to encode data for all OFDM frame types
// For the moment will will send all carriers with the same mode (I don't think there is an advantage being different),
// So we can use a different block length in each mode. We need to keep record of which blocks within bytDataToSend have
// been acked. Note that the first block is always unacked - acked data at the front of buffer is removed.
// Although we have an 8 bit sequence, I don't see the need for more than 128 outstanding blocks (carriers). If we miss
// just the first block of a 43 frame transmission, next time we send block 1 and 44 - 86. If 1 is still the only one
// unacked I will repeat it several times in the next transmission, which will be the repeats plus 87 - 127.
// Unfortunately this means bytDataToSend must be at least 128 * max block size (80) = 10240, which is a lot on a Teensy.
// Maybe can come upwith better design!
UCHAR UnackedOFDMBlocks [ 128 ] = { 0 } ; // This is bit list of outstanding blocks.
UCHAR UnackedOFDMBlockLen [ 128 ] = { 0 } ; // Length of each block. do we need both (ie can we send a block of zero length ??)
int NextOFDMBlock = 0 ;
int UnAckedBlockPtr = 0 ;
int CarriersSent ;
int BytesSent = 0 ; // Sent but not acked
int CarriersACKed ;
int CarriersNAKed ;
int lastOFDMRXMode ;
int LastDemodType = 0 ;
int OFDMLevel ; // % "compression"
// This is used if we send a partial block. Will normally only happen
// at end of transmission, but could due to flow control
//
// Also used if we want to change mode
int DontSendNewData = 0 ; // Dont send new till all acked
int LimitNewData = 0 ; // Repeat unacked several times till all acked
int NeedShiftDown = 0 ; // Shift down once all sent
int Duplicate = 0 ; // Send data twice
int firstNewCarrier = 0 ;
UCHAR SentOFDMBlocks [ MAXCAR ] ;
UCHAR SentOFDMBlockLen [ MAXCAR ] ; // Must match actual carrier number
UCHAR OFDMBlocks [ MAXCAR ] ; // Build the carrier set in here
UCHAR OFDMBlockLen [ MAXCAR ] ;
UCHAR goodReceivedBlocks [ 128 ] ;
UCHAR goodReceivedBlockLen [ 128 ] ;
# define MAX_RAW_LENGTH_FSK 43 // 1 + 32 + 8 + 2
# define MAX_RAW_LENGTH 163 // Len Byte + Data + RS + CRC I think!
int BytesSenttoHost = 0 ;
extern UCHAR bytData [ 128 * 80 ] ;
extern int bytQDataInProcessLen ;
extern UCHAR bytSessionID ;
extern UCHAR bytFrameData [ 10 ] [ MAX_RAW_LENGTH + 10 ] ; // Received chars
extern char CarrierOk [ MAXCAR ] ; // RS OK Flags per carrier
extern double dblPhaseInc ; // in milliradians
extern short intNforGoertzel [ MAXCAR ] ;
extern short intPSKPhase_1 [ MAXCAR ] , intPSKPhase_0 [ MAXCAR ] ;
extern short intCP [ MAXCAR ] ; // Cyclic prefix offset
extern float dblFreqBin [ MAXCAR ] ;
extern short intFilteredMixedSamples [ ] ; // Get Frame Type need 2400 and we may add 1200
extern int intFilteredMixedSamplesLength ;
extern int MaxFilteredMixedSamplesLength ;
extern short intCarMagThreshold [ MAXCAR ] ;
extern short * * intMags ;
extern short * * intPhases ;
extern float floatCarFreq ; //(was int) // Are these the same ??
extern int intNumCar ;
extern int intSampPerSym ;
extern int intDataLen ;
extern int intRSLen ;
extern int SymbolsLeft ;
extern int intPhasesLen ;
extern int intPhasesLen ;
extern int intPSKMode ;
extern int intSymbolsPerByte ;
extern int PSKInitDone ;
extern int intLastRcvdFrameQuality ;
extern int frameLen ;
extern int intFrameType ;
extern const char Good [ MAXCAR ] ;
extern const char Bad [ MAXCAR ] ;
extern int pskStart ;
extern int charIndex ; // Index into received chars
extern int RepeatedFrame ; // set if this data frame is a repeat
extern int intShiftUpDn ;
extern int dttTimeoutTrip ;
extern int LastDataFrameType ; // Last data frame processed (for Memory ARQ, etc)
extern int intNAKctr ;
extern int intACKctr ;
extern int intTimeouts ;
2024-10-29 22:45:21 +00:00
void ARDOPSampleSink ( short Sample ) ;
2023-09-04 19:06:44 +01:00
extern UCHAR goodReceivedBlocks [ 128 ] ;
extern UCHAR goodReceivedBlockLen [ 128 ] ;
void GoertzelRealImag ( short intRealIn [ ] , int intPtr , int N , float m , float * dblReal , float * dblImag ) ;
int ComputeAng1_Ang2 ( int intAng1 , int intAng2 ) ;
int Demod1CarOFDMChar ( int Start , int Carrier , int intNumOfSymbols ) ;
VOID Decode1CarPSK ( int Carrier , BOOL OFDM ) ;
int CorrectRawDataWithRS ( UCHAR * bytRawData , UCHAR * bytCorrectedData , int intDataLen , int intRSLen , int bytFrameType , int Carrier ) ;
UCHAR GetSym8PSK ( int intDataPtr , int k , int intCar , UCHAR * bytEncodedBytes , int intDataBytesPerCar ) ;
int Track1CarPSK ( int floatCarFreq , int PSKMode , BOOL QAM , BOOL OFDM , float dblUnfilteredPhase , BOOL blnInit ) ;
void SendLeaderAndSYNC ( UCHAR * bytEncodedBytes , int intLeaderLen ) ;
void ARDOPFlush ( ) ;
BOOL CheckCRC16 ( unsigned char * Data , int Length ) ;
void CorrectPhaseForTuningOffset ( short * intPhase , int intPhaseLength , int intPSKMode ) ;
BOOL DemodOFDM ( ) ;
void GenCRC16Normal ( char * Data , int Length )
{
unsigned int CRC = GenCRC16 ( Data , Length ) ;
// Put the two CRC bytes after the stop index
Data [ Length + + ] = ( CRC > > 8 ) ; // MS 8 bits of Register
Data [ Length ] = ( CRC & 0xFF ) ; // LS 8 bits of Register
}
void ClearOFDMVariables ( )
{
OFDMMode = PSK4 ;
memset ( UnackedOFDMBlocks , 0 , sizeof ( UnackedOFDMBlocks ) ) ;
memset ( UnackedOFDMBlockLen , 0 , sizeof ( UnackedOFDMBlockLen ) ) ;
NextOFDMBlock = 0 ;
BytesSent = 0 ;
SavedOFDMMode = - 1 ;
DontSendNewData = LimitNewData = Duplicate = 0 ;
memset ( SentOFDMBlocks , 0 , sizeof ( SentOFDMBlocks ) ) ;
memset ( SentOFDMBlockLen , 0 , sizeof ( SentOFDMBlockLen ) ) ;
CarriersACKed = CarriersNAKed = NeedShiftDown = 0 ;
lastOFDMRXMode = LastDemodType = 0 ;
}
int GetNextOFDMBlockNumber ( int * Len )
{
BOOL Looping = 0 ;
resend :
while ( UnAckedBlockPtr > = 0 )
{
if ( UnackedOFDMBlocks [ UnAckedBlockPtr ] )
{
* Len = UnackedOFDMBlockLen [ UnAckedBlockPtr - - ] ;
return UnAckedBlockPtr + 1 ; // We send unacked blocks backwards
}
UnAckedBlockPtr - - ;
}
if ( LimitNewData )
{
Debugprintf ( " LimitNewData Set - repeating unacked blocks " ) ;
UnAckedBlockPtr = 127 ; // Send unacked again
LimitNewData - - ;
goto resend ;
}
if ( DontSendNewData & & Looping = = 0 )
{
Debugprintf ( " DontSendNewData Set - repeating unacked blocks " ) ;
UnAckedBlockPtr = 127 ; // Send unacked again
Looping = 1 ; // Protect against loop
goto resend ;
}
// No unacked blocks, send new
NextOFDMBlock + + ;
* Len = - 1 ;
return NextOFDMBlock - 1 ;
}
UCHAR * GetNextOFDMBlock ( int Block , int intDataLen )
{
return 0 ; & bytDataToSend [ Block * intDataLen ] ;
}
void GetOFDMFrameInfo ( int OFDMMode , int * intDataLen , int * intRSLen , int * Mode , int * Symbols )
{
switch ( OFDMMode )
{
case PSK2 :
* intDataLen = 19 ;
* intRSLen = 6 ; // Must be even
* Symbols = 8 ;
* Mode = 2 ;
break ;
case PSK4 :
* intDataLen = 40 ;
* intRSLen = 10 ;
* Symbols = 4 ;
* Mode = 4 ;
break ;
case PSK8 :
* intDataLen = 57 ; // Must be multiple of 3
* intRSLen = 18 ; // Must be multiple of 3 and even (so multiple of 6)
* Symbols = 8 ; // Actually 8 symbols for 3 bytes
* Mode = 8 ;
break ;
case PSK16 :
* intDataLen = 80 ;
* intRSLen = 20 ;
* Symbols = 2 ;
* Mode = 16 ;
break ;
case QAM16 :
* intDataLen = 80 ;
* intRSLen = 20 ;
* Symbols = 2 ;
* Mode = 8 ;
break ;
case QAM32 :
* intDataLen = 100 ;
* intRSLen = 25 ;
* Symbols = 8 ; // Actually 8 symbols for 3 bytes
* Mode = 16 ;
break ;
case PSK4S :
* intDataLen = 12 ;
* intRSLen = 4 ;
* Symbols = 4 ;
* Mode = 4 ;
break ;
default :
* intDataLen = * intRSLen = 0 ;
}
}
int EncodeOFDMData ( UCHAR bytFrameType , UCHAR * bytDataToSend , int Length , unsigned char * bytEncodedBytes )
{
// Output is a byte array which includes:
// 1) A 2 byte Header which include the Frame ID. This will be sent using 4FSK at 50 baud. It will include the Frame ID and ID Xored by the Session bytID.
// 2) n sections one for each carrier that will include all data (with FEC appended) for the entire frame. Each block will be identical in length.
// Each carrier starts with an 8 bit block number, which may not be sequential (each carrier is ack'ed separately)
// and may be repeated (for redundancy)
// OFDM Has several modes, selected by OFDMMode not Frame Type (all are OFDM.500 or OFDM.2500
// For the moment will will send all carriers wirh the same mode (I don't think there is an advantage being different),
// So we can use a different block length in each mode. We need to keep record of which blocks within bytDataToSend have
// been acked. Note that the first block is always unacked - acked data at the front of buffer is removed.
int intNumCar , intBaud , intDataLen , intRSLen , bytDataToSendLengthPtr , intEncodedDataPtr ;
int intCarDataCnt ;
BOOL blnOdd ;
char strType [ 18 ] ;
char strMod [ 16 ] ;
BOOL blnFrameTypeOK ;
UCHAR bytQualThresh ;
int i , j , Dummy ;
UCHAR * bytToRS = & bytEncodedBytes [ 2 ] ;
int RepeatIndex = 0 ; // used to duplicate data if too short to fill frame
blnFrameTypeOK = FrameInfo ( bytFrameType , & blnOdd , & intNumCar , strMod , & intBaud , & intDataLen , & intRSLen , & bytQualThresh , strType ) ;
if ( intDataLen = = 0 | | Length = = 0 | | ! blnFrameTypeOK )
return 0 ;
GetOFDMFrameInfo ( OFDMMode , & intDataLen , & intRSLen , & Dummy , & Dummy ) ;
// Generate the 2 bytes for the frame type data:
CarriersSent = intNumCar ;
bytEncodedBytes [ 0 ] = bytFrameType ;
bytEncodedBytes [ 1 ] = bytFrameType ^ bytSessionID ;
bytDataToSendLengthPtr = 0 ;
firstNewCarrier = - 1 ;
intEncodedDataPtr = 2 ;
UnAckedBlockPtr = 127 ; // We send unacked blocks backwards
// Length is data still queued. BytesSent is unacked data
Length - = BytesSent ; // New data to send
if ( Length = = 0 )
DontSendNewData = 1 ;
Debugprintf ( " OFDM Bytes to Send %d DontSendNewData %d " , Length , DontSendNewData ) ;
// Often the first carrier is the only one missed, and if we repeat it first it will always
// fail. So it would be good if logical block number 0 isn't always sent on carrier 0
// The carrier number must match the block number so we can ack it.
for ( i = 0 ; i < intNumCar ; i + + ) // across all carriers
{
int blkLen ;
int blkNum ;
intCarDataCnt = Length - bytDataToSendLengthPtr ;
// If we have no new data to send we would repeat the last sent blocks from
// SentOFDMBlocks which is wrong if there is no new data. So in that case just
// send outstanding data.
if ( DontSendNewData & & BytesSent ) // Just send outstanding data repeatedly if necessary
{
OFDMBlocks [ i ] = blkNum = GetNextOFDMBlockNumber ( & blkLen ) ;
OFDMBlockLen [ i ] = UnackedOFDMBlockLen [ blkNum ] = blkLen ;
UnackedOFDMBlocks [ blkNum ] = 1 ;
}
else if ( Duplicate & ( i > = ( ( intNumCar - firstNewCarrier ) / 2 ) ) )
goto repeatblocks ;
else if ( intCarDataCnt > intDataLen ) // why not > ??
{
// Won't all fit
tryagain :
OFDMBlocks [ i ] = blkNum = GetNextOFDMBlockNumber ( & blkLen ) ;
if ( blkLen = = - 1 )
{
// New Block. Make sure it will fit in window
int limit ;
if ( intNumCar = = 9 )
limit = 24 ; // Don't want too many outstanding or shift up will be slow
else
limit = 125 ;
if ( firstNewCarrier = = - 1 )
firstNewCarrier = i ;
if ( ( NextOFDMBlock + ( intNumCar - i ) ) > limit )
{
// no room
NextOFDMBlock - - ; // we aren't going to send it
UnAckedBlockPtr = 127 ; // send unacked again
goto tryagain ;
}
blkLen = intDataLen ;
bytDataToSendLengthPtr + = intDataLen ; // Don't reduce bytes to send if repeating
BytesSent + = intDataLen ;
}
OFDMBlockLen [ i ] = UnackedOFDMBlockLen [ blkNum ] = blkLen ;
UnackedOFDMBlocks [ blkNum ] = 1 ;
}
else
{
// Last bit
memset ( & bytToRS [ 0 ] , 0 , intDataLen ) ;
bytToRS [ 0 ] = intCarDataCnt ; // Could be 0 if insuffient data for # of carriers
if ( intCarDataCnt > 0 )
{
OFDMBlocks [ i ] = blkNum = GetNextOFDMBlockNumber ( & blkLen ) ;
if ( blkLen = = - 1 )
{
if ( firstNewCarrier = = - 1 )
firstNewCarrier = i ;
blkLen = intCarDataCnt ; // Could be 0 if insuffient data for # of carriers
bytDataToSendLengthPtr + = intCarDataCnt ; // Don't reduce bytes to send if repeating
BytesSent + = intCarDataCnt ;
if ( intCarDataCnt < intDataLen )
DontSendNewData = TRUE ; // sending a part block so mustnt send more till all acked
}
UnackedOFDMBlockLen [ blkNum ] = OFDMBlockLen [ i ] = blkLen ;
UnackedOFDMBlocks [ blkNum ] = 1 ;
}
else
{
// No more data to send - duplicate sent carriers. Gives extra redundancy
repeatblocks :
blkNum = OFDMBlocks [ RepeatIndex ] ;
blkLen = OFDMBlockLen [ RepeatIndex + + ] ;
OFDMBlocks [ i ] = blkNum ;
OFDMBlockLen [ i ] = blkLen ;
UnackedOFDMBlockLen [ blkNum ] = blkLen ;
UnackedOFDMBlocks [ blkNum ] = 1 ;
}
}
}
// We now have pointers to the logical blocks in OFDMBlocks/Len. We don't
// have to modulate in that order, but must update SentOFDMBlocks with the real
// Carrier number
j = rand ( ) % intNumCar ;
for ( i = 0 ; i < intNumCar ; i + + )
{
if ( j > = intNumCar )
j = 0 ;
SentOFDMBlockLen [ i ] = bytToRS [ 0 ] = OFDMBlockLen [ j ] ;
SentOFDMBlocks [ i ] = bytToRS [ 1 ] = OFDMBlocks [ j + + ] ;
Debugprintf ( " Sending OFDM Carrier %d Block %d Len %d " , i , bytToRS [ 1 ] , bytToRS [ 0 ] ) ;
memcpy ( & bytToRS [ 2 ] , GetNextOFDMBlock ( bytToRS [ 1 ] , intDataLen ) , bytToRS [ 0 ] ) ;
GenCRC16Normal ( bytToRS , intDataLen + 2 ) ; // calculate the CRC on the byte count + data bytes
// Data + RS + 1 byte byteCount + 1 byte blockno + 2 Byte CRC
RSEncode ( bytToRS , bytToRS + intDataLen + 4 , intDataLen + 4 , intRSLen ) ; // Generate the RS encoding
intEncodedDataPtr + = intDataLen + 4 + intRSLen ;
bytToRS + = intDataLen + 4 + intRSLen ;
}
return intEncodedDataPtr ;
}
// OFDM RX Routines
extern int NErrors ;
BOOL Decode4FSKOFDMACK ( )
{
BOOL FrameOK ;
BOOL blnRSOK ;
// 6 Byte payload, 2 CRC 4 RS
if ( CheckCRC16 ( & bytFrameData [ 0 ] [ 0 ] , 6 ) )
{
Debugprintf ( " OFDMACK Decode OK " ) ;
return TRUE ;
}
// Try RS Correction
FrameOK = RSDecode ( & bytFrameData [ 0 ] [ 0 ] , 12 , 4 , & blnRSOK ) ;
if ( FrameOK & & blnRSOK = = FALSE )
{
// RS Claims to have corrected it, but check
Debugprintf ( " OFDMACK %d Errors Corrected by RS " , NErrors ) ;
if ( CheckCRC16 ( & bytFrameData [ 0 ] [ 0 ] , 6 ) )
{
Debugprintf ( " OFDMACK Corrected by RS OK " ) ;
return TRUE ;
}
}
Debugprintf ( " OFDMACK Decode Failed after RS " ) ;
return FALSE ;
}
void RemoveProcessedOFDMData ( )
{
// ISS has changed toggle, so last ack was processed.
// if the last frame wasn't completely decoded then we need to remove any data sent to host and corresponding
// entries in goodReceivedBlocks and goodReceivedBlockLen
// This allows us to accumulate carriers from repeated frames. This could be good for FEC, but I think it is
// of limited value for ARQ. Is it worth it ???
int i , n , Len = 0 ;
for ( i = 0 ; i < 128 ; i + + )
{
n = goodReceivedBlockLen [ i ] ;
if ( n )
Len + = n ;
else
break ; // exit loop on first missed block.
}
// i is number of blocks to remove
if ( i = = 0 )
return ;
Debugprintf ( " Removing %d received OFDM blocks Length %d " , i , Len ) ;
memmove ( goodReceivedBlocks , & goodReceivedBlocks [ i ] , 128 - i ) ;
memmove ( goodReceivedBlockLen , & goodReceivedBlockLen [ i ] , 128 - i ) ;
memset ( & goodReceivedBlocks [ 128 - i ] , 0 , i ) ;
memset ( & goodReceivedBlockLen [ 128 - i ] , 0 , i ) ;
memmove ( bytData , & bytData [ Len ] , sizeof ( bytData ) - Len ) ;
}
VOID InitDemodOFDM ( )
{
// Called at start of frame
int i ;
float dblPhase , dblReal , dblImag ;
short modePhase [ MAXCAR ] [ 3 ] ;
int OFDMType [ MAXCAR ] = { 0 } ;
int ModeCount [ 8 ] = { 0 } ;
int MaxModeCount = 0 ;
char Msg [ 64 ] ;
intSampPerSym = 240 ;
floatCarFreq = 1500.0f + ( ( intNumCar / 2 ) * 10000.0f ) / 180.0f ; // Top freq (spacing is 10000/180)
for ( i = 0 ; i < intNumCar ; i + + )
{
// OFDM uses 55.5555 Hz carrier interval
intCP [ i ] = 24 ; //CP length
intNforGoertzel [ i ] = 216 ;
dblFreqBin [ i ] = floatCarFreq / 55.5555f ;
// Get initial Reference Phase
GoertzelRealImag ( intFilteredMixedSamples , intCP [ i ] , intNforGoertzel [ i ] , dblFreqBin [ i ] , & dblReal , & dblImag ) ;
dblPhase = atan2f ( dblImag , dblReal ) ;
// Set initial mag from Reference Phase and Mode Bits (which should be full power)
intCarMagThreshold [ i ] = sqrtf ( powf ( dblReal , 2 ) + powf ( dblImag , 2 ) ) ;
intPSKPhase_1 [ i ] = 1000 * dblPhase ;
// Get the 3 OFDM mode bits
GoertzelRealImag ( intFilteredMixedSamples + 240 , intCP [ i ] , intNforGoertzel [ i ] , dblFreqBin [ i ] , & dblReal , & dblImag ) ;
dblPhase = atan2f ( dblImag , dblReal ) ;
intPSKPhase_0 [ i ] = 1000 * atan2f ( dblImag , dblReal ) ;
modePhase [ i ] [ 0 ] = - ( ComputeAng1_Ang2 ( intPSKPhase_0 [ i ] , intPSKPhase_1 [ i ] ) ) ;
intPSKPhase_1 [ i ] = intPSKPhase_0 [ i ] ;
intCarMagThreshold [ i ] + = sqrtf ( powf ( dblReal , 2 ) + powf ( dblImag , 2 ) ) ;
GoertzelRealImag ( intFilteredMixedSamples + 480 , intCP [ i ] , intNforGoertzel [ i ] , dblFreqBin [ i ] , & dblReal , & dblImag ) ;
dblPhase = atan2f ( dblImag , dblReal ) ;
intPSKPhase_0 [ i ] = 1000 * atan2f ( dblImag , dblReal ) ;
modePhase [ i ] [ 1 ] = - ( ComputeAng1_Ang2 ( intPSKPhase_0 [ i ] , intPSKPhase_1 [ i ] ) ) ;
intPSKPhase_1 [ i ] = intPSKPhase_0 [ i ] ;
intCarMagThreshold [ i ] + = sqrtf ( powf ( dblReal , 2 ) + powf ( dblImag , 2 ) ) ;
GoertzelRealImag ( intFilteredMixedSamples + 720 , intCP [ i ] , intNforGoertzel [ i ] , dblFreqBin [ i ] , & dblReal , & dblImag ) ;
dblPhase = atan2f ( dblImag , dblReal ) ;
intPSKPhase_0 [ i ] = 1000 * atan2f ( dblImag , dblReal ) ;
modePhase [ i ] [ 2 ] = - ( ComputeAng1_Ang2 ( intPSKPhase_0 [ i ] , intPSKPhase_1 [ i ] ) ) ;
intPSKPhase_1 [ i ] = intPSKPhase_0 [ i ] ;
intCarMagThreshold [ i ] + = sqrtf ( powf ( dblReal , 2 ) + powf ( dblImag , 2 ) ) ;
intCarMagThreshold [ i ] * = 0.75f ;
// We have accumulated 4 values so divide by 4
intCarMagThreshold [ i ] / = 4.0f ;
if ( modePhase [ i ] [ 0 ] > = 1572 | | modePhase [ i ] [ 0 ] < = - 1572 )
OFDMType [ i ] | = 1 ;
if ( modePhase [ i ] [ 1 ] > = 1572 | | modePhase [ i ] [ 1 ] < = - 1572 )
OFDMType [ i ] | = 2 ;
if ( modePhase [ i ] [ 2 ] > = 1572 | | modePhase [ i ] [ 2 ] < = - 1572 )
OFDMType [ i ] | = 4 ;
floatCarFreq - = 55.555664f ; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing.
}
// Get RX Mode. May be corrupt on some carriers, so go with majority
// But incorrectly seeing a change will cause corruption, so perhaps
// need more than simple majority
// Or maybe don't actually clear old data until we decode at least
// one frame. That way an incorrect frame type won't cause a problem
// (as frame won't decode). But what if type is correct and frame still
// won't decode ??
// So if almost all types aren't the same, and type is new, discard.
for ( i = 0 ; i < intNumCar ; i + + )
ModeCount [ OFDMType [ i ] ] + + ;
for ( i = 0 ; i < 8 ; i + + )
{
if ( ModeCount [ i ] > MaxModeCount )
{
MaxModeCount = ModeCount [ i ] ;
RXOFDMMode = i ;
}
}
if ( MaxModeCount ! = intNumCar )
Debugprintf ( " Not all OFDM Types the same (%d) " , intNumCar - MaxModeCount ) ;
if ( RXOFDMMode ! = lastOFDMRXMode )
{
// has changed. Only accept if all ok
// ?? is this a bit extreme ??. Try 1 error
if ( MaxModeCount < ( intNumCar - 1 ) )
{
// Not sure. Safer to assume wrong
// if it really has changed decode will fail
// and frame repeat
RXOFDMMode = lastOFDMRXMode ;
Debugprintf ( " New OFDM Mode but more than 1 carrier different (%d) - assume corrupt and don't change " , intNumCar - MaxModeCount ) ;
}
}
GetOFDMFrameInfo ( RXOFDMMode , & intDataLen , & intRSLen , & intPSKMode , & intSymbolsPerByte ) ;
// if OFDM mode (or frame type) has changed clear any received but unprocessed data
// If we aren't going to decode because it is a repeat we don't need to
// check, as type can't have changed, and new type might be corrupt
if ( ! RepeatedFrame | | ( memcmp ( CarrierOk , Bad , intNumCar ) = = 0 ) )
{
// We are going to decode it, so check
if ( RXOFDMMode ! = lastOFDMRXMode | | ( intFrameType & 0xFE ) ! = ( LastDemodType & 0xFE ) )
{
memset ( goodReceivedBlocks , 0 , sizeof ( goodReceivedBlocks ) ) ;
memset ( goodReceivedBlockLen , 0 , sizeof ( goodReceivedBlockLen ) ) ;
BytesSenttoHost = 0 ;
lastOFDMRXMode = RXOFDMMode ;
if ( ( intFrameType & 0xFE ) ! = ( LastDemodType & 0xFE ) )
Debugprintf ( " New OFDM Mode - clear any received data " ) ;
else
Debugprintf ( " New Frame Type - clear any received data " ) ;
}
}
Track1CarPSK ( floatCarFreq , intPSKMode , FALSE , TRUE , dblPhase , TRUE ) ;
SymbolsLeft = intDataLen + intRSLen + 4 ; // Data has length Blockno and CRC
dblPhaseInc = 2 * M_PI * 1000 / intPSKMode ;
intPhasesLen = 0 ;
PSKInitDone = TRUE ;
Debugprintf ( " OFDM Mode %s " , OFDMModes [ RXOFDMMode ] ) ;
sprintf ( Msg , " %s/%s " , Name ( intFrameType ) , OFDMModes [ RXOFDMMode ] ) ;
DrawRXFrame ( 0 , Msg ) ;
}
VOID Decode1CarOFDM ( int Carrier )
{
unsigned int intData ;
int k ;
float dblAlpha = 0.1f ; // this determins how quickly the rolling average dblTrackingThreshold responds.
// dblAlpha value of .1 seems to work well...needs to be tested on fading channel (e.g. Multipath)
int Threshold = intCarMagThreshold [ Carrier ] ;
int Len = intPhasesLen ;
UCHAR * Decoded = bytFrameData [ 0 ] ; // Always use first buffer
pskStart = 0 ;
charIndex = 0 ;
// We calculated initial mag from reference symbol
// use filtered tracking of refernce phase amplitude
// (should be full amplitude value)
// On WGN this appears to improve decoding threshold about 1 dB 9/3/2016
while ( Len > = 0 )
{
// Phase Samples are in intPhases
intData = 0 ;
for ( k = 0 ; k < 2 ; k + + )
{
intData < < = 4 ;
if ( intPhases [ Carrier ] [ pskStart ] < 393 & & intPhases [ Carrier ] [ pskStart ] > - 393 )
{
} // Zero so no need to do anything
else if ( intPhases [ Carrier ] [ pskStart ] > = 393 & & intPhases [ Carrier ] [ pskStart ] < 1179 )
intData + = 1 ;
else if ( intPhases [ Carrier ] [ pskStart ] > = 1179 & & intPhases [ Carrier ] [ pskStart ] < 1965 )
intData + = 2 ;
else if ( intPhases [ Carrier ] [ pskStart ] > = 1965 & & intPhases [ Carrier ] [ pskStart ] < 2751 )
intData + = 3 ;
else if ( intPhases [ Carrier ] [ pskStart ] > = 2751 | | intPhases [ Carrier ] [ pskStart ] < - 2751 )
intData + = 4 ;
else if ( intPhases [ Carrier ] [ pskStart ] > = - 2751 & & intPhases [ Carrier ] [ pskStart ] < - 1965 )
intData + = 5 ;
else if ( intPhases [ Carrier ] [ pskStart ] > = - 1965 & & intPhases [ Carrier ] [ pskStart ] < = - 1179 )
intData + = 6 ;
else
intData + = 7 ;
if ( intMags [ Carrier ] [ pskStart ] < Threshold )
{
intData + = 8 ; // add 8 to "inner circle" symbols.
Threshold = ( Threshold * 900 + intMags [ Carrier ] [ pskStart ] * 150 ) / 1000 ;
}
else
{
Threshold = ( Threshold * 900 + intMags [ Carrier ] [ pskStart ] * 75 ) / 1000 ;
}
intCarMagThreshold [ Carrier ] = Threshold ;
pskStart + + ;
}
Decoded [ charIndex + + ] = intData ;
Len - = 2 ;
}
}
BOOL DemodOFDM ( )
{
int Used = 0 ;
int Start = 0 ;
int i , n , MemARQOk = 0 ;
int skip = rand ( ) % intNumCar ;
// We can't wait for the full frame as we don't have enough RAM, so
// we do one DMA Buffer at a time, until we run out or end of frame
// Only continue if we have enough samples
while ( State = = AcquireFrame )
{
if ( PSKInitDone = = 0 ) // First time through
{
if ( intFilteredMixedSamplesLength < ( 240 * 4 ) ) // Reference and 3 Mode bits
return FALSE ;
InitDemodOFDM ( ) ;
intFilteredMixedSamplesLength - = 4 * intSampPerSym ;
if ( intFilteredMixedSamplesLength < 0 )
Debugprintf ( " Corrupt intFilteredMixedSamplesLength " ) ;
Start + = 4 * intSampPerSym ;
// We normally don't decode Repeated frames. But if all carriers failed to
// decode we should
if ( RepeatedFrame )
{
if ( memcmp ( CarrierOk , Bad , intNumCar ) = = 0 )
RepeatedFrame = FALSE ;
}
}
if ( intFilteredMixedSamplesLength < intSymbolsPerByte * intSampPerSym + 10 )
{
// Move any unprocessessed data down buffer
// (while checking process - will use cyclic buffer eventually
if ( intFilteredMixedSamplesLength > 0 )
memmove ( intFilteredMixedSamples ,
& intFilteredMixedSamples [ Start ] , intFilteredMixedSamplesLength * 2 ) ;
return FALSE ;
}
// call the decode char routine for each carrier
// start at the highest carrier freq which is actually the lowest transmitted carrier due to Reverse sideband mixing
floatCarFreq = 1500.0f + ( ( intNumCar / 2 ) * 10000.0f ) / 180.0f ; // spacing is 10000/180 = 55.5555555
for ( i = 0 ; i < intNumCar ; i + + )
{
Used = Demod1CarOFDMChar ( Start , i , intSymbolsPerByte ) ; // demods 2 phase values - enough for one char
intPhasesLen - = intSymbolsPerByte ;
floatCarFreq - = 55.555664f ; // Step through each carrier Highest to lowest which is equivalent to lowest to highest before RSB mixing.
}
intPhasesLen + = intSymbolsPerByte ;
if ( RXOFDMMode = = PSK8 )
SymbolsLeft - = 3 ;
else
SymbolsLeft - - ; // number still to decode
Start + = Used ;
intFilteredMixedSamplesLength - = Used ;
if ( intFilteredMixedSamplesLength < 0 )
Debugprintf ( " Corrupt intFilteredMixedSamplesLength " ) ;
if ( SymbolsLeft < = 0 )
{
// Frame complete - decode it
DecodeCompleteTime = Now ;
// prepare for next so we can exit when we have finished decode
DiscardOldSamples ( ) ;
ClearAllMixedSamples ( ) ;
State = SearchingForLeader ;
// Rick uses the last carrier for Quality
// Get quality from middle carrier (?? is this best ??
intLastRcvdFrameQuality = UpdatePhaseConstellation ( & intPhases [ intNumCar / 2 ] [ 0 ] , & intMags [ intNumCar / 2 ] [ 0 ] , intPSKMode , FALSE , TRUE ) ;
// Decode the phases. Mode was determined from header
frameLen = 0 ;
if ( RepeatedFrame )
{
Debugprintf ( " Repeated frame - discard " ) ;
frameLen = BytesSenttoHost ;
return TRUE ;
}
for ( i = 0 ; i < intNumCar ; i + + )
{
UCHAR decodeBuff [ 256 ] ; // 82 doesnt seem to be enough ??Max length of OFDM block
int decodeLen , ofdmBlock ; ;
CarrierOk [ i ] = 0 ; // Always reprocess carriers
if ( RXOFDMMode = = QAM16 )
Decode1CarOFDM ( i ) ;
else
Decode1CarPSK ( i , TRUE ) ;
// with OFDM each carrier has a sequence number, as we can do selective repeats if a carrier is missed.
// so decode into a separate buffer, and copy good data into the correct place in the received data buffer.
decodeLen = CorrectRawDataWithRS ( & bytFrameData [ 0 ] [ 0 ] , decodeBuff , intDataLen + 1 , intRSLen , intFrameType , i ) ;
// if decode fails try with a tuning offset correction
if ( CarrierOk [ i ] = = 0 )
{
CorrectPhaseForTuningOffset ( & intPhases [ i ] [ 0 ] , intPhasesLen , intPSKMode ) ;
if ( RXOFDMMode = = QAM16 )
Decode1CarOFDM ( i ) ;
else
Decode1CarPSK ( i , TRUE ) ;
decodeLen = CorrectRawDataWithRS ( & bytFrameData [ 0 ] [ 0 ] , decodeBuff , intDataLen + 1 , intRSLen , intFrameType , i ) ;
}
OFDMCarriersReceived [ RXOFDMMode ] + + ;
if ( CarrierOk [ i ] )
{
ofdmBlock = decodeBuff [ 0 ] ;
// CRC check isn't perfect. At least we can check that Block and Length
// are reasonable
if ( ofdmBlock < 128 & & decodeLen < = intDataLen )
{
// copy data to correct place in bytData
OFDMCarriersDecoded [ RXOFDMMode ] + + ;
if ( goodReceivedBlocks [ ofdmBlock ] = = 0 )
{
memcpy ( & bytData [ intDataLen * ofdmBlock ] , & decodeBuff [ 1 ] , decodeLen ) ;
goodReceivedBlocks [ ofdmBlock ] = 1 ;
goodReceivedBlockLen [ ofdmBlock ] = decodeLen ;
}
}
}
}
// Pass any contiguous blocks starting from 0 to host (may need to reconsider!)
for ( i = 0 ; i < 128 ; i + + )
{
n = goodReceivedBlockLen [ i ] ;
if ( n )
frameLen + = n ;
else
break ; // exit loop on first missed block.
}
// If this is a repeated frame, we should only send any data that is beyond what we sent at last try
BytesSenttoHost = frameLen ;
}
// if all carriers have been decoded we must have passed all data to the host, so clear partial receive info
if ( memcmp ( CarrierOk , Good , intNumCar ) = = 0 )
{
memset ( goodReceivedBlocks , 0 , sizeof ( goodReceivedBlocks ) ) ;
memset ( goodReceivedBlockLen , 0 , sizeof ( goodReceivedBlockLen ) ) ;
BytesSenttoHost = 0 ;
}
}
return TRUE ;
}
int Demod1CarOFDMChar ( int Start , int Carrier , int intNumOfSymbols )
{
// Converts intSample to an array of differential phase and magnitude values for the Specific Carrier Freq
// intPtr should be pointing to the approximate start of the first reference/training symbol (1 of 3)
// intPhase() is an array of phase values (in milliradians range of 0 to 6283) for each symbol
// intMag() is an array of Magnitude values (not used in PSK decoding but for constellation plotting or QAM decoding)
// Objective is to use Minimum Phase Error Tracking to maintain optimum pointer position
// It demodulates one byte's worth of samples (2 or 4)
float dblReal , dblImag , dblPhase ;
int intMiliRadPerSample = floatCarFreq * M_PI / 6 ;
int i ;
int origStart = Start ;
// int Corrections;
// With OFDM we save received data in Receive buffer, so don't keep
// the raw frames. So we must always decode
if ( RepeatedFrame ) // We just repeat previous ack/nak, so don't bother to decode
{
intPhasesLen + = intNumOfSymbols ;
return intSampPerSym * intNumOfSymbols ;
}
for ( i = 0 ; i < intNumOfSymbols ; i + + )
{
GoertzelRealImag ( intFilteredMixedSamples , Start + intCP [ Carrier ] , intNforGoertzel [ Carrier ] , dblFreqBin [ Carrier ] , & dblReal , & dblImag ) ;
intMags [ Carrier ] [ intPhasesLen ] = sqrtf ( powf ( dblReal , 2 ) + powf ( dblImag , 2 ) ) ;
dblPhase = atan2f ( dblImag , dblReal ) ;
intPSKPhase_0 [ Carrier ] = 1000 * dblPhase ;
intPhases [ Carrier ] [ intPhasesLen ] = - ( ComputeAng1_Ang2 ( intPSKPhase_0 [ Carrier ] , intPSKPhase_1 [ Carrier ] ) ) ;
// Should we track each carrier ??
/*
if ( Carrier = = 0 )
{
Corrections = Track1CarPSK ( floatCarFreq , intPSKMode , FALSE , TRUE , dblPhase , FALSE ) ;
if ( Corrections ! = 0 )
{
Start + = Corrections ;
GoertzelRealImag ( intFilteredMixedSamples , Start + intCP [ Carrier ] , intNforGoertzel [ Carrier ] , dblFreqBin [ Carrier ] , & dblReal , & dblImag ) ;
intPSKPhase_0 [ Carrier ] = 1000 * atan2f ( dblImag , dblReal ) ;
}
}
*/
intPSKPhase_1 [ Carrier ] = intPSKPhase_0 [ Carrier ] ;
intPhasesLen + + ;
Start + = intSampPerSym ;
}
if ( AccumulateStats )
intOFDMSymbolCnt + = intNumOfSymbols ;
return ( Start - origStart ) ; // Symbols we've consumed
}
VOID EncodeAndSendOFDMACK ( UCHAR bytSessionID , int LeaderLength , int Chan )
{
// OFDMACK has one bit per carrier. As this needs 43 bits meassage is 6 bytes. The spare 5 bits are
// used to send quality
unsigned long long val = intLastRcvdFrameQuality > > 2 ;
int i ;
// Not sure if best to use CRC or FEC. Could use both, but message gets a bit long.
// Lets go with crc for now
// Now try CRC and 4 RS. OTT but see if it reduces number
// of failed OFDMACKs
bytEncodedBytes [ 0 ] = OFDMACK ;
bytEncodedBytes [ 1 ] = OFDMACK ^ bytSessionID ;
for ( i = MAXCAR - 1 ; i > = 0 ; i - - )
{
val < < = 1 ;
if ( CarrierOk [ i ] )
val | = 1 ;
}
for ( i = 2 ; i < 8 ; i + + )
{
bytEncodedBytes [ i ] = val & 0xff ;
val > > = 8 ;
}
GenCRC16Normal ( & bytEncodedBytes [ 2 ] , 6 ) ; // calculate the CRC
RSEncode ( & bytEncodedBytes [ 2 ] , & bytEncodedBytes [ 10 ] , 8 , 4 ) ; // Generate the RS encoding ...now 14 bytes total
Mod4FSKDataAndPlay ( & bytEncodedBytes [ 0 ] , 14 , LeaderLength , Chan ) ;
}
UCHAR bytLastSym [ 43 ] ;
float dblOFDMCarRatio = 0.5f ;
void SendOFDM2PSK ( int symbol , int intNumCar )
{
int intCarIndex = ( MAXCAR - intNumCar ) / 2 ;
int intSample ;
int OFDMFrame [ 240 ] = { 0 } ; // accumulated samples for each carrier
short OFDMSamples [ 240 ] ; // 216 data, 24 CP
int i , n , p , q ; // start at 24, copy CP later
for ( i = 0 ; i < intNumCar ; i + + ) // across all active carriers
{
p = 24 ;
memset ( OFDMSamples , 0 , sizeof ( OFDMSamples ) ) ;
for ( n = 0 ; n < 216 ; n + + )
{
if ( symbol )
OFDMSamples [ p + + ] - = intOFDMTemplate [ intCarIndex ] [ 0 ] [ n ] ;
else
OFDMSamples [ p + + ] + = intOFDMTemplate [ intCarIndex ] [ 0 ] [ n ] ;
}
// we now have the 216 samples. Copy last 24 to front as CP
memcpy ( OFDMSamples , & OFDMSamples [ 216 ] , 24 * 2 ) ;
// and add into the multicarrier value
for ( q = 0 ; q < 240 ; q + + )
OFDMFrame [ q ] + = OFDMSamples [ q ] ;
// now do the next carrier
bytLastSym [ intCarIndex ] = symbol ;
intCarIndex + + ;
}
// Done all carriers - send sample
for ( q = 0 ; q < 240 ; q + + )
{
intSample = OFDMFrame [ q ] / intNumCar ;
ARDOPSampleSink ( ( intSample * OFDMLevel ) / 100 ) ;
}
}
void ModOFDMDataAndPlay ( unsigned char * bytEncodedBytes , int Len , int intLeaderLen , int Chan )
{
int intNumCar , intBaud , intDataLen , intRSLen , intDataPtr , intSampPerSym , intDataBytesPerCar ;
BOOL blnOdd ;
int Type = bytEncodedBytes [ 0 ] ;
int intSample ;
char strType [ 18 ] = " " ;
char strMod [ 16 ] = " " ;
UCHAR bytSym , bytSymToSend , bytMinQualThresh ;
float dblCarScalingFactor ;
int intMask = 0 ;
int intLeaderLenMS ;
int i , j , k , s , n ;
int intCarStartIndex ;
int intPeakAmp ;
int intCarIndex ;
BOOL QAM = 0 ;
int OFDMFrame [ 240 ] = { 0 } ; // accumulated samples for each carrier
short OFDMSamples [ 240 ] ; // 216 data, 24 CP
int p , q ; // start at 24, copy CP later
char fType [ 64 ] ;
if ( ! FrameInfo ( Type , & blnOdd , & intNumCar , strMod , & intBaud , & intDataLen , & intRSLen , & bytMinQualThresh , strType ) )
return ;
intDataBytesPerCar = ( Len - 2 ) / intNumCar ; // We queue the samples here, so dont copy below
intCarIndex = intCarStartIndex = ( MAXCAR - intNumCar ) / 2 ;
switch ( OFDMMode )
{
case PSK2 :
s = 8 ; // 8 symbols per byte
break ;
case PSK4 :
case PSK4S :
s = 4 ; // 4 symbols per byte
break ;
case PSK8 :
s = 8 ; // 8 symbols for 3 bytes
break ;
case PSK16 :
s = 2 ; // 2 symbols per byte
break ;
case QAM16 :
s = 2 ; // 2 symbols per byte
QAM = 1 ;
break ;
default :
Debugprintf ( " Undefined OFDM Mode %d " , OFDMMode ) ;
return ;
}
intSampPerSym = 216 ; // 55 baud
if ( Type = = PktFrameData )
{
intDataBytesPerCar = pktDataLen + pktRSLen + 3 ;
intDataPtr = 11 ; // Over Header
goto PktLoopBack ;
}
Debugprintf ( " Sending Frame Type %s Mode %s " , strType , OFDMModes [ OFDMMode ] ) ;
sprintf ( fType , " %s/%s " , strType , OFDMModes [ OFDMMode ] ) ;
DrawTXFrame ( fType ) ;
if ( intNumCar = = 3 )
{
initFilter ( 500 , 1500 , Chan ) ;
OFDMLevel = 80 ;
}
else if ( intNumCar = = 9 )
{
initFilter ( 500 , 1500 , Chan ) ;
OFDMLevel = 100 ;
}
else
{
initFilter ( 2500 , 1500 , Chan ) ;
OFDMLevel = 125 ;
}
if ( intLeaderLen = = 0 )
intLeaderLenMS = LeaderLength ;
else
intLeaderLenMS = intLeaderLen ;
// Create the leader
SendLeaderAndSYNC ( bytEncodedBytes , intLeaderLen ) ;
intPeakAmp = 0 ;
intDataPtr = 2 ; // initialize pointer to start of data.
PktLoopBack : // Reenter here to send rest of variable length packet frame
// Now create a reference symbol for each carrier
// We have to do each carrier for each sample, as we write
// the sample immediately
SendOFDM2PSK ( 0 , intNumCar ) ; // Reference symbol is always zero, so same in any mode
// Now send OFDM Type as 3 x 2PSK symbols. Same value sent on all carriers. The Type is send as 2PSK
// bytLastSym ends up correct
bytSym = ( OFDMMode ) & 1 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 1 ) ; // Values 0=1
SendOFDM2PSK ( bytSymToSend , intNumCar ) ;
bytSym = ( OFDMMode > > 1 ) & 1 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 1 ) ; // Values 0-1
SendOFDM2PSK ( bytSymToSend , intNumCar ) ;
bytSym = ( OFDMMode > > 2 ) & 1 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 1 ) ; // Values 0-1
SendOFDM2PSK ( bytSymToSend , intNumCar ) ;
// Correct bytLastSYM to match PSK level of actual mode
for ( i = intCarStartIndex ; i < intCarStartIndex + intNumCar ; i + + )
{
if ( OFDMMode = = PSK4 | | OFDMMode = = PSK4S )
bytLastSym [ i ] < < = 1 ;
else if ( OFDMMode = = PSK8 | | OFDMMode = = QAM16 )
bytLastSym [ i ] < < = 2 ;
if ( OFDMMode = = PSK16 )
bytLastSym [ i ] < < = 3 ;
}
// Unlike ARDOP_WIN we send samples as they are created,
// so we loop through carriers, then data bytes
for ( j = 0 ; j < intDataBytesPerCar ; j + + ) // for each referance and data symbol
{
// Loop through each symbol of byte (4 for PSK 2 for QAM
for ( k = 0 ; k < s ; k + + )
{
// with OFDM we must create separate samples for each
// carrier, so we can add the cyclic prefix
intCarIndex = intCarStartIndex ; // initialize the carrrier index
for ( i = 0 ; i < intNumCar ; i + + ) // across all active carriers
{
if ( OFDMMode = = PSK2 )
{
bytSym = ( bytEncodedBytes [ intDataPtr + i * intDataBytesPerCar ] > > ( ( 7 - k ) ) ) & 1 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 1 ) ; // Values 0-1
}
else if ( OFDMMode = = PSK4 | | OFDMMode = = PSK4S )
{
bytSym = ( bytEncodedBytes [ intDataPtr + i * intDataBytesPerCar ] > > ( 2 * ( 3 - k ) ) ) & 3 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 3 ) ; // Values 0-3
}
else if ( OFDMMode = = PSK8 )
{
// More complex ...must go through data in 3 byte chunks creating 8 Three bit symbols for each 3 bytes of data.
bytSym = GetSym8PSK ( intDataPtr , k , i , bytEncodedBytes , intDataBytesPerCar ) ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 7 ) ; // mod 8
}
else if ( OFDMMode = = PSK16 )
{
bytSym = ( bytEncodedBytes [ intDataPtr + i * intDataBytesPerCar ] > > ( 4 * ( 1 - k ) ) ) & 15 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] + bytSym ) & 15 ) ; // Values 0-3
}
else
{
// 16QAM
bytSym = ( bytEncodedBytes [ intDataPtr + i * intDataBytesPerCar ] > > ( 4 * ( 1 - k ) ) ) & 15 ;
bytSymToSend = ( ( bytLastSym [ intCarIndex ] & 7 ) + ( bytSym & 7 ) & 7 ) ; // Compute the differential phase to send
bytSymToSend = bytSymToSend | ( bytSym & 8 ) ; // add in the amplitude bit directly from symbol
}
p = 24 ;
memset ( OFDMSamples , 0 , sizeof ( OFDMSamples ) ) ;
for ( n = 0 ; n < intSampPerSym ; n + + )
{
if ( OFDMMode = = PSK2 )
{
if ( bytSymToSend ) // This uses the symmetry of the symbols to reduce the table size by a factor of 2
OFDMSamples [ p + + ] - = intOFDMTemplate [ intCarIndex ] [ 0 ] [ n ] ;
else
OFDMSamples [ p + + ] + = intOFDMTemplate [ intCarIndex ] [ 0 ] [ n ] ;
}
else if ( OFDMMode = = PSK4 | | OFDMMode = = PSK4S )
{
if ( bytSymToSend < 2 ) // This uses the symmetry of the symbols to reduce the table size by a factor of 2
OFDMSamples [ p + + ] + = intOFDMTemplate [ intCarIndex ] [ 4 * bytSymToSend ] [ n ] ; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols)
else
OFDMSamples [ p + + ] - = intOFDMTemplate [ intCarIndex ] [ 4 * ( bytSymToSend - 2 ) ] [ n ] ; // subtract 2 from the symbol value before doubling and subtract value of table
}
else if ( OFDMMode = = PSK16 )
{
if ( bytSymToSend < 8 ) // This uses the symmetry of the symbols to reduce the table size by a factor of 2
OFDMSamples [ p + + ] + = intOFDMTemplate [ intCarIndex ] [ bytSymToSend ] [ n ] ; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols)
else
OFDMSamples [ p + + ] - = intOFDMTemplate [ intCarIndex ] [ ( bytSymToSend - 8 ) ] [ n ] ; // subtract 2 from the symbol value before doubling and subtract value of table
}
else
{
// This works for both 8PSK and 16QAM as 8PSK does'nt have the ampiltude bit
// 4bits/symbol (use table symbol values 0, 1, 2, 3, -0, -1, -2, -3) and modulate amplitude with MSB
if ( bytSymToSend < 4 ) // This uses the symmetry of the symbols to reduce the table size by a factor of 2
OFDMSamples [ p + + ] = intOFDMTemplate [ intCarIndex ] [ 2 * bytSymToSend ] [ n ] ; // double the symbol value during template lookup for 4PSK. (skips over odd PSK 8 symbols)
else if ( bytSymToSend < 8 )
OFDMSamples [ p + + ] = - intOFDMTemplate [ intCarIndex ] [ 2 * ( bytSymToSend - 4 ) ] [ n ] ; // subtract 4 from the symbol value before doubling and subtract value of table
else if ( bytSymToSend < 12 )
OFDMSamples [ p + + ] = dblOFDMCarRatio * intOFDMTemplate [ intCarIndex ] [ 2 * ( bytSymToSend - 8 ) ] [ n ] ; // subtract 4 from the symbol value before doubling and subtract value of table
else
OFDMSamples [ p + + ] = - dblOFDMCarRatio * intOFDMTemplate [ intCarIndex ] [ 2 * ( bytSymToSend - 12 ) ] [ n ] ; // subtract 4 from the symbol value before doubling and subtract value of table
}
}
// we now have the 216 samples. Copy last 24 to front as CP
memcpy ( OFDMSamples , & OFDMSamples [ 216 ] , 24 * 2 ) ;
// and add into the multicarrier value
for ( q = 0 ; q < 240 ; q + + )
OFDMFrame [ q ] + = OFDMSamples [ q ] ;
// now do the next carrier
bytLastSym [ intCarIndex ] = bytSymToSend ;
intCarIndex + + ;
}
// Done all carriers - send sample
for ( q = 0 ; q < 240 ; q + + )
{
intSample = OFDMFrame [ q ] / intNumCar ;
ARDOPSampleSink ( ( intSample * OFDMLevel ) / 100 ) ;
OFDMFrame [ q ] = 0 ;
}
}
if ( OFDMMode = = PSK8 )
{
intDataPtr + = 3 ;
j + = 2 ; // We've used 3 bytes
}
else
intDataPtr + + ;
}
if ( Type = = PktFrameHeader )
{
// just sent packet header. Send rest in current mode
Type = 0 ; // Prevent reentry
strcpy ( strMod , & pktMod [ pktMode ] [ 0 ] ) ;
intDataBytesPerCar = pktDataLen + pktRSLen + 3 ;
intDataPtr = 11 ; // Over Header
intNumCar = pktCarriers [ pktMode ] ;
switch ( intNumCar )
{
case 1 :
intCarStartIndex = 4 ;
// dblCarScalingFactor = 1.0f; // Starting at 1500 Hz (scaling factors determined emperically to minimize crest factor) TODO: needs verification
dblCarScalingFactor = 1.2f ; // Starting at 1500 Hz Selected to give < 13% clipped values yielding a PAPR = 1.6 Constellation Quality >98
case 2 :
intCarStartIndex = 3 ;
// dblCarScalingFactor = 0.53f;
if ( strcmp ( strMod , " 16QAM " ) = = 0 )
dblCarScalingFactor = 0.67f ; // Carriers at 1400 and 1600 Selected to give < 2.5% clipped values yielding a PAPR = 2.17, Constellation Quality >92
else
dblCarScalingFactor = 0.65f ; // Carriers at 1400 and 1600 Selected to give < 4% clipped values yielding a PAPR = 2.0, Constellation Quality >95
break ;
case 4 :
intCarStartIndex = 2 ;
// dblCarScalingFactor = 0.29f; // Starting at 1200 Hz
dblCarScalingFactor = 0.4f ; // Starting at 1200 Hz Selected to give < 3% clipped values yielding a PAPR = 2.26, Constellation Quality >95
break ;
case 8 :
intCarStartIndex = 0 ;
// dblCarScalingFactor = 0.17f; // Starting at 800 Hz
if ( strcmp ( strMod , " 16QAM " ) = = 0 )
dblCarScalingFactor = 0.27f ; // Starting at 800 Hz Selected to give < 1% clipped values yielding a PAPR = 2.64, Constellation Quality >94
else
dblCarScalingFactor = 0.25f ; // Starting at 800 Hz Selected to give < 2% clipped values yielding a PAPR = 2.5, Constellation Quality >95
}
goto PktLoopBack ; // Reenter to send rest of variable length packet frame
}
ARDOPFlush ( ) ;
}
// Function to compute a 16 bit CRC value and check it against the last 2 bytes of Data (the CRC)
unsigned short int compute_crc ( unsigned char * buf , int len ) ;
BOOL CheckCRC16 ( unsigned char * Data , int Length )
{
// returns TRUE if CRC matches, else FALSE
// For CRC-16-CCITT = x^16 + x^12 +x^5 + 1 intPoly = 1021 Init FFFF
// intSeed is the seed value for the shift register and must be in the range 0-0xFFFF
unsigned int CRC = GenCRC16 ( Data , Length ) ;
unsigned short CRC2 = compute_crc ( Data , Length ) ;
CRC2 ^ = 0xffff ;
// Compare the register with the last two bytes of Data (the CRC)
if ( ( CRC > > 8 ) = = Data [ Length ] )
if ( ( CRC & 0xFF ) = = Data [ Length + 1 ] )
return TRUE ;
return FALSE ;
}
// Subroutine to get intDataLen bytes from outbound queue (bytDataToSend)