Still migrate

This commit is contained in:
F5OEO
2018-03-21 14:47:53 +00:00
parent 334576a845
commit 2380f37340
52 changed files with 1 additions and 10073 deletions

121
am/piam.c
View File

@@ -1,121 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <math.h>
#include <sndfile.h>
#define ln(x) (log(x)/log(2.718281828459045235f))
#define BUFFER_LEN 1024*8
int FileFreqTiming;
// Test program using SNDFILE
// see http://www.mega-nerd.com/libsndfile/api.html for API
void WriteTone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=Frequency;
RfSample.WaitForThisSample=Timing; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming,&RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
int main(int argc, char **argv) {
float data [2*BUFFER_LEN] ;
float data_filtered[2*BUFFER_LEN] ; // we generate complex I/Q samples
SNDFILE *infile, *outfile ;
SF_INFO sfinfo ;
int readcount, nb_samples ;
char *infilename ;
char *outfilename ;
int k ;
float x ;
if( argc < 2 ) {
printf("Usage : %s in.wav [out.wav]\n", argv[0]);
return(1);
}
infilename = argv[1];
if( argc == 3 ) {
outfilename = argv[2];
} else {
outfilename = (char *)malloc( 128 );
sprintf( outfilename, "%s", "out.ft");
}
if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
{ /* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename);
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL));
return 1;
}
if( sfinfo.samplerate != 48000 ) {
printf("Input rate must be 48K.\n");
return 1;
}
FileFreqTiming = open(outfilename, O_WRONLY|O_CREAT, 0644);
/** **/
printf ("Reading file : %s\n", infilename );
printf ("Sample Rate : %d\n", sfinfo.samplerate);
printf ("Channels : %d\n", sfinfo.channels);
printf ("----------------------------------------\n");
printf ("Writing file : %s\n", outfilename );
/* While there are.frames in the input file, read them, process
** them and write them to the output file.
*/
while ((readcount = sf_readf_float(infile, data, BUFFER_LEN)))
{
nb_samples = readcount / sfinfo.channels;
for( k=0 ; k < nb_samples ; k++ ) {
x = data[k*sfinfo.channels];
if( sfinfo.channels == 2 ) {
// stereo file, avg left + right
x += data[k*sfinfo.channels+1];
x /= 2;
}
//printf("%f \n",x);
float FactAmplitude=2.0; // To be analyzed more deeply !
/*
double A = 87.7f; // compression parameter
double ampf=x/32767.0;
ampf = (fabs(ampf) < 1.0f/A) ? A*fabs(ampf)/(1.0f+ln(A)) : (1.0f+ln(A*fabs(ampf)))/(1.0f+ln(A)); //compand
x= (int)(round(ampf * 32767.0f));
*/
WriteTone(x*32767*FactAmplitude,1e9/48000.0);
}
}
/* Close input and output files. */
sf_close (infile) ;
close(FileFreqTiming);
return 0;
}

View File

@@ -1,254 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
// Get main process from arduino project : CodingGhost/DCF77-Transmitter
// Generator for 77,5 kHz (DCF-77) by Jonas woerner (c)
// Thanks to Jonas
// Evariste F5OEO 2015
//!!!!ONLY FOR TESTING PURPOSES!
#define byte char
#define false 0
#define true 1
byte dcfBits[60] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
#define anzahlMinutenBits 7
#define anzahlStundenBits 6
#define offsetMinutenBits 21
#define offsetStundenBits 29
byte MinutenBits[anzahlMinutenBits] = { 0 };
byte StundenBits[anzahlStundenBits] = { 0 };
int parity = 0;
int FileFreqTiming;
void modulate(byte b);
void playtone(double Amplitude,uint32_t Timing);
void loop()
{
int i;
for (i = 0; i<58; ++i)
{
modulate(dcfBits[i]);
}
}
void DCF_BITS(int Minuten, int Stunden)
{
int i;
//MINUTE
if (Minuten > 39)
{
MinutenBits[6] = 1;
Minuten -= 40;
}
if (Minuten > 19)
{
MinutenBits[5] = 1;
Minuten -= 20;
}
if (Minuten > 9)
{
MinutenBits[4] = 1;
Minuten -= 10;
}
for ( i = 0; i < 4; ++i)
{
//MinutenBits[i] = (Minuten & (1 << i)) ? true : false;
if ((Minuten & (1 << i)) > 0)
{
MinutenBits[i] = true;
}
else
{
MinutenBits[i] = false;
}
}
for ( i = 0; i < anzahlMinutenBits; ++i)
{
dcfBits[offsetMinutenBits + i] = MinutenBits[i];
}
//Stunde
if (Stunden > 19)
{
StundenBits[5] = 1;
Stunden -= 20;
}
if (Stunden > 9)
{
StundenBits[4] = 1;
Stunden -= 10;
}
for ( i = 0; i < 4; ++i)
{
//MinutenBits[i] = (Minuten & (1 << i)) ? true : false;
if ((Stunden & (1 << i)) > 0)
{
StundenBits[i] = true;
}
else
{
StundenBits[i] = false;
}
}
for ( i = 0; i < anzahlStundenBits; ++i)
{
dcfBits[offsetStundenBits + i] = StundenBits[i];
}
/*for (int n = 0; n < 6; ++n)
{
}*/
////////////////////////////
{
parity += dcfBits[21];
parity += dcfBits[22];
parity += dcfBits[23];
parity += dcfBits[24];
parity += dcfBits[25];
parity += dcfBits[26];
parity += dcfBits[27];
//dcfBits[28] = parity % 2; ???
if (parity % 2 == 0)
{
dcfBits[28] = 0;
}
else
{
dcfBits[28] = 1;
}
parity = 0;
}
////////////////////////////
{
parity += dcfBits[29];
parity += dcfBits[30];
parity += dcfBits[31];
parity += dcfBits[32];
parity += dcfBits[33];
parity += dcfBits[34];
if (parity % 2 == 0)
{
dcfBits[35] = 0;
}
else
{
dcfBits[35] = 1;
}
parity = 0;
}
/////////////////////////////
{
parity += dcfBits[36];
parity += dcfBits[37];
parity += dcfBits[38];
parity += dcfBits[39];
parity += dcfBits[40];
parity += dcfBits[41];
parity += dcfBits[42];
parity += dcfBits[43];
parity += dcfBits[44];
parity += dcfBits[45];
parity += dcfBits[46];
parity += dcfBits[47];
parity += dcfBits[48];
parity += dcfBits[49];
parity += dcfBits[50];
parity += dcfBits[51];
parity += dcfBits[52];
parity += dcfBits[53];
parity += dcfBits[54];
parity += dcfBits[55];
parity += dcfBits[56];
parity += dcfBits[57];
if (parity % 2 == 0)
{
dcfBits[58] = 0;
}
else
{
dcfBits[58] = 1;
}
parity = 0;
}
}
void modulate(byte b)
{
if (b == 0)
{
playtone(32667/8,100e6);
playtone(32767,900e6);
}
else
{
playtone(32767/8,200e6);
playtone(32767,800e6);
}
}
void playtone(double Amplitude,uint32_t Timing)
{
typedef struct {
double Amplitude;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Amplitude=Amplitude;
RfSample.WaitForThisSample=Timing; //en 100 de nanosecond
printf("%f %d\n",Amplitude,Timing);
if (write(FileFreqTiming, &RfSample, sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
int main(int argc, char **argv)
{
if (argc > 1)
{
char *sFileFreqTiming=(char *)argv[1];
FileFreqTiming = open(argv[1], O_WRONLY|O_CREAT, 0644);
DCF_BITS(7,59);
loop();
playtone(0,1000e6);//last second
close(FileFreqTiming);
}
else
{
printf("usage : pidfc77 dcfpatern.bin\n");
exit(0);
}
return 0;
}

View File

@@ -1,140 +0,0 @@
//
// Simple FSQ beacon for Arduino, with the Etherkit Si5351A Breakout
// Board, by Jason Milldrum NT7S.
//
// Original code based on Feld Hell beacon for Arduino by Mark
// Vandewettering K6HX, adapted for the Si5351A by Robert
// Liesenfeld AK6L <ak6l@ak6l.org>. Timer setup
// code by Thomas Knutsen LA3PNA.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#define TONE_SPACING 8789 // ~8.7890625 Hz
#define BAUD_2 7812 // CTC value for 2 baud
#define BAUD_3 5208 // CTC value for 3 baud
#define BAUD_4_5 3472 // CTC value for 4.5 baud
#define BAUD_6 2604 // CTC value for 6 baud
#define LED_PIN 13
#define bool char
#define false 0
#define true 1
// Global variables
unsigned long freq = 0;//7105350; // Base freq is 1350 Hz higher than dial freq in USB
uint8_t cur_tone = 0;
static uint8_t crc8_table[256];
char callsign[10] = "F5OEO";
char tx_buffer[40];
uint8_t callsign_crc;
int FileText;
int FileFreqTiming;
// Global variables used in ISRs
volatile bool proceed = false;
void WriteTone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=Frequency;
RfSample.WaitForThisSample=Timing; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming, &RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
int main(int argc, char **argv)
{
char *sText;
if (argc > 2)
{
sText=(char *)argv[1];
//FileText = open(argv[1], O_RDONLY);
char *sFileFreqTiming=(char *)argv[2];
FileFreqTiming = open(argv[2], O_WRONLY|O_CREAT);
}
else
{
printf("usage : pidrone StringToTransmit file.ft\n");
exit(0);
}
//100KHZ
int Freq_span = 100000;
int NbStep = 2000;
int i;
for(i=1;i<NbStep;i++)
{
WriteTone(Freq_span*i/NbStep-Freq_span/2,1000e6/NbStep);
}
WriteTone(00000,250e6);
for (i=0;i<strlen(sText);i++)
{
int bit;
WriteTone(25000,1250e3);//Start bit
for(bit=0;bit<8;bit++)
{
if((sText[i]&(1<<(7-bit)))>0)
{
WriteTone(25000,1250e3);
printf("1");
}
else
{
WriteTone(-25000,1250e3);
printf("0");
}
}
WriteTone(25000,1250e3);//Stop bit
printf("\n");
}
WriteTone(00000,250e6);
close(FileFreqTiming);
}

109
fm/pifm.c
View File

@@ -1,109 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sndfile.h>
#define BUFFER_LEN 1024*8
int FileFreqTiming;
// Test program using SNDFILE
// see http://www.mega-nerd.com/libsndfile/api.html for API
void WriteTone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=Frequency;
RfSample.WaitForThisSample=Timing; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming, &RfSample, sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
int main(int argc, char **argv)
{
float data [2*BUFFER_LEN];
float data_filtered[2*BUFFER_LEN]; // we generate complex I/Q samples
SNDFILE *infile, *outfile;
SF_INFO sfinfo;
int readcount, nb_samples;
char *infilename;
char *outfilename;
int k;
float x;
if( argc < 2 ) {
printf("Usage : %s in.wav [out.wav]\n", argv[0]);
return(1);
}
infilename = argv[1];
if( argc == 3 ) {
outfilename = argv[2];
} else {
outfilename = (char *)malloc( 128 );
sprintf( outfilename, "%s", "out.ft");
}
if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
{ /* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename);
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL));
return 1;
}
if( sfinfo.samplerate != 48000 ) {
printf("Input rate must be 48K.\n");
return 1;
}
FileFreqTiming = open(outfilename, O_WRONLY|O_CREAT, 0644);
/** **/
printf ("Reading file : %s\n", infilename ) ;
printf ("Sample Rate : %d\n", sfinfo.samplerate) ;
printf ("Channels : %d\n", sfinfo.channels) ;
printf ("----------------------------------------\n") ;
printf ("Writing file : %s\n", outfilename ) ;
/* While there are.frames in the input file, read them, process
** them and write them to the output file.
*/
int Excursion=6000;
while ((readcount = sf_readf_float(infile, data, BUFFER_LEN)))
{
nb_samples = readcount / sfinfo.channels ;
for( k=0 ; k < nb_samples ; k++ ) {
x = data[k*sfinfo.channels] ;
if( sfinfo.channels == 2 ) {
// stereo file, avg left + right
x += data[k*sfinfo.channels+1] ;
x /= 2 ;
}
//printf("%f \n",x);
WriteTone(x*Excursion*2.0,1e9/48000.0);
}
}
/* Close input and output files. */
sf_close (infile) ;
close(FileFreqTiming);
return 0;
}

View File

@@ -1,379 +0,0 @@
//
// Simple FSQ beacon for Arduino, with the Etherkit Si5351A Breakout
// Board, by Jason Milldrum NT7S.
//
// Original code based on Feld Hell beacon for Arduino by Mark
// Vandewettering K6HX, adapted for the Si5351A by Robert
// Liesenfeld AK6L <ak6l@ak6l.org>. Timer setup
// code by Thomas Knutsen LA3PNA.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#define TONE_SPACING 8789 // ~8.7890625 Hz
#define BAUD_2 7812 // CTC value for 2 baud
#define BAUD_3 5208 // CTC value for 3 baud
#define BAUD_4_5 3472 // CTC value for 4.5 baud
#define BAUD_6 2604 // CTC value for 6 baud
#define LED_PIN 13
#define bool char
#define false 0
#define true 1
// Global variables
unsigned long freq = 0;//7105350; // Base freq is 1350 Hz higher than dial freq in USB
uint8_t cur_tone = 0;
static uint8_t crc8_table[256];
char callsign[10] = "F5OEO";
char tx_buffer[40];
uint8_t callsign_crc;
int FileText;
int FileFreqTiming;
// Global variables used in ISRs
volatile bool proceed = false;
// Define the structure of a varicode table
typedef struct fsq_varicode
{
uint8_t ch;
uint8_t var[2];
} Varicode;
// The FSQ varicode table, based on the FSQ Varicode V3.0
// document provided by Murray Greenman, ZL1BPU
const Varicode code_table[] =
{
{' ', {00, 00}}, // space
{'!', {11, 30}},
{'"', {12, 30}},
{'#', {13, 30}},
{'$', {14, 30}},
{'%', {15, 30}},
{'&', {16, 30}},
{'\'', {17, 30}},
{'(', {18, 30}},
{')', {19, 30}},
{'*', {20, 30}},
{'+', {21, 30}},
{',', {27, 29}},
{'-', {22, 30}},
{'.', {27, 00}},
{'/', {23, 30}},
{'0', {10, 30}},
{'1', {01, 30}},
{'2', {02, 30}},
{'3', {03, 30}},
{'4', {04, 30}},
{'5', {05, 30}},
{'6', {06, 30}},
{'7', {07, 30}},
{'8', {8, 30}},
{'9', {9, 30}},
{':', {24, 30}},
{';', {25, 30}},
{'<', {26, 30}},
{'=', {00, 31}},
{'>', {27, 30}},
{'?', {28, 29}},
{'@', {00, 29}},
{'A', {01, 29}},
{'B', {02, 29}},
{'C', {03, 29}},
{'D', {04, 29}},
{'E', {05, 29}},
{'F', {06, 29}},
{'G', {07, 29}},
{'H', {8, 29}},
{'I', {9, 29}},
{'J', {10, 29}},
{'K', {11, 29}},
{'L', {12, 29}},
{'M', {13, 29}},
{'N', {14, 29}},
{'O', {15, 29}},
{'P', {16, 29}},
{'Q', {17, 29}},
{'R', {18, 29}},
{'S', {19, 29}},
{'T', {20, 29}},
{'U', {21, 29}},
{'V', {22, 29}},
{'W', {23, 29}},
{'X', {24, 29}},
{'Y', {25, 29}},
{'Z', {26, 29}},
{'[', {01, 31}},
{'\\', {02, 31}},
{']', {03, 31}},
{'^', {04, 31}},
{'_', {05, 31}},
{'`', {9, 31}},
{'a', {01, 00}},
{'b', {02, 00}},
{'c', {03, 00}},
{'d', {04, 00}},
{'e', {05, 00}},
{'f', {06, 00}},
{'g', {07, 00}},
{'h', {8, 00}},
{'i', {9, 00}},
{'j', {10, 00}},
{'k', {11, 00}},
{'l', {12, 00}},
{'m', {13, 00}},
{'n', {14, 00}},
{'o', {15, 00}},
{'p', {16, 00}},
{'q', {17, 00}},
{'r', {18, 00}},
{'s', {19, 00}},
{'t', {20, 00}},
{'u', {21, 00}},
{'v', {22, 00}},
{'w', {23, 00}},
{'x', {24, 00}},
{'y', {25, 00}},
{'z', {26, 00}},
{'{', {06, 31}},
{'|', {07, 31}},
{'}', {8, 31}},
{'~', {00, 30}},
{127, {28, 31}}, // DEL
{13, {28, 00}}, // CR
{10, {28, 00}}, // LF
{0, {28, 30}}, // IDLE
{241, {10, 31}}, // plus/minus
{246, {11, 31}}, // division sign
{248, {12, 31}}, // degrees sign
{158, {13, 31}}, // multiply sign
{156, {14, 31}}, // pound sterling sign
{8, {27, 31}} // BS
};
void encode_tone(uint8_t tone);
// Define an upper bound on the number of glyphs. Defining it this
// way allows adding characters without having to update a hard-coded
// upper bound.
#define NGLYPHS (sizeof(code_table)/sizeof(code_table[0]))
// Timer interrupt vector. This toggles the variable we use to gate
// each column of output to ensure accurate timing. Called whenever
// Timer1 hits the count set below in setup().
/*ISR(TIMER1_COMPA_vect)
{
proceed = true;
}
*/
// This is the heart of the beacon. Given a character, it finds the
// appropriate glyph and sets output from the Si5351A to key the
// FSQ signal.
void WriteTone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=Frequency;
RfSample.WaitForThisSample=Timing*1000L; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming, &RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
void encode_char(int ch)
{
uint8_t i, fch, vcode1, vcode2;
for(i = 0; i < NGLYPHS; i++)
{
// Check each element of the varicode table to see if we've found the
// character we're trying to send.
fch = code_table[i].ch;
if(fch == ch)
{
// Found the character, now fetch the varicode chars
vcode1 = code_table[i].var[0];
vcode2 = code_table[i].var[1];
// Transmit the appropriate tone per a varicode char
if(vcode2 == 0)
{
// If the 2nd varicode char is a 0 in the table,
// we are transmitting a lowercase character, and thus
// only transmit one tone for this character.
// Generate tone
encode_tone(vcode1);
}
else
{
// If the 2nd varicode char is anything other than 0 in
// the table, then we need to transmit both
// Generate 1st tone
encode_tone(vcode1);
// Generate 2nd tone
encode_tone(vcode2);
}
break; // We've found and transmitted the char,
// so exit the for loop
}
}
}
void encode_tone(uint8_t tone)
{
cur_tone = ((cur_tone + tone + 1) % 33);
//printf("Current tone =%d\n",cur_tone);
WriteTone(1000 + (cur_tone * TONE_SPACING*0.001),500000L);
//TO DO FREQUENCY PI si5351.set_freq((freq * 100) + (cur_tone * TONE_SPACING), 0, SI5351_CLK0);
}
// Loop through the string, transmitting one character at a time.
void encode(char *str)
{
// Reset the tone to 0 and turn on the output
cur_tone = 0;
/*
si5351.output_enable(SI5351_CLK0, 1);
digitalWrite(LED_PIN, HIGH);
*/
//Serial.println("=======");
// Transmit BOT
//noInterrupts();
encode_char(' '); // Send a space for the dummy character
//Do wait
// Send another space
encode_char(' ');
//Do wait
// Now send LF
encode_char(10);
//Do wait
// Now do the rest of the message
while (*str != '\0')
{
encode_char(*str++);
}
// Turn off the output
//si5351.output_enable(SI5351_CLK0, 0);
//digitalWrite(LED_PIN, LOW);
}
static void init_crc8(void)
{
int i,j;
uint8_t crc;
for(i = 0; i < 256; i++)
{
crc = i;
for(j = 0; j < 8; j++)
{
crc = (crc << 1) ^ ((crc & 0x80) ? 0x07 : 0);
}
crc8_table[i] = crc & 0xFF;
}
}
uint8_t crc8(char * text)
{
uint8_t crc='\0';
uint8_t ch;
int i;
for(i = 0; i < strlen(text); i++)
{
ch = text[i];
crc = crc8_table[(crc) ^ ch];
crc &= 0xFF;
}
return crc;
}
int main(int argc, char **argv)
{
char *sText;
if (argc > 2)
{
sText=(char *)argv[1];
//FileText = open(argv[1], O_RDONLY);
char *sFileFreqTiming=(char *)argv[2];
FileFreqTiming = open(argv[2], O_WRONLY|O_CREAT, 0644);
}
else
{
printf("usage : pifsq StringToTransmit file.ft\n");
exit(0);
}
// Initialize the CRC table
init_crc8();
// Generate the CRC for the callsign
callsign_crc = crc8(callsign);
// We are building a directed message here, but you can do whatever.
// So apparently, FSQ very specifically needs " \b " in
// directed mode to indicate EOT. A single backspace won't do it.
sprintf(tx_buffer, "%s:%02x%s%s", callsign, callsign_crc,sText," \b ");
encode(tx_buffer);
int i;
for(i=0;i<10;i++)
{
WriteTone(0,500000L);
}
close(FileFreqTiming);
}

View File

@@ -1,761 +0,0 @@
// OPERA_Decode_Test.cpp : Defines the entry point for the console application.
//
// Purpose : to study coding and decoding of OPERA which was developed by EA5HVK.
//
// Usage : "OPERA_Decode_Test [? | d | s | w]
// where : s= help, d = debug, s = AA1AA and w = 7L1RLL
//
// Version : 1.0.3, 11/27/2015 change print_char() to print_str()
// Version : 1.0.2, 11/27/2015 bug fix at unpack(), and add 7L1RLL as a 2nd sample.
// Version : 1.0.1, 11/27/2015 Add a function of print_char()
// Version : 1.0.0, 11/25/2015 Initial Release, but under construction on error correction.
//
// Copyright : 7L1RLL(Rick Wakatori) 2015 under Terms of The GNU General
// Public License.
//
// Environments : Microsoft Visual C++ 2010 Express under Windows 10.
// Compiler version : 10.0.40219.1 SPIRel
//
// Acknowledgements :
// a)EA5HVK(Jose) for work on OPERA
// b)F4GCB(Patrick) for PIC program on CRC16 which is a copy into this program.
// c)PE1NNZ(Guido), for Article titled Opera Protocol Specification.
//#include "stdafx.h"
#include "stdio.h"
#include "math.h"
#include "string.h"
short int call_AA1AA[239] =
{ // callsign = "AA1AA"
1,0,1,1, 0,1,0,0, 1,0,1,1, 0,0,1,0, // 0xB4, 0xB2
1,1,0,0, 1,1,0,1, 0,0,1,1, 0,0,1,0, // 0xCD, 0x32
1,0,1,0, 1,1,0,0, 1,0,1,1, 0,0,1,1, // 0xAC, 0xB3
0,1,0,0, 1,0,1,0, 1,1,0,0, 1,1,0,0, // 0x4A, 0xCC
1,1,0,0, 1,1,0,1, 0,0,1,1, 0,0,1,0, // 0xCD, 0x32
1,0,1,0, 1,0,1,1, 0,0,1,1, 0,1,0,1, // 0xA9, 0x35
0,1,0,0, 1,1,0,0, 1,1,0,1, 0,1,0,0, // 0x4C, 0xD4
1,0,1,1, 0,1,0,0, 1,0,1,0, 1,1,0,1, // 0xB4, 0xAD
0,0,1,1, 0,1,0,0, 1,1,0,1, 0,1,0,0, // 0x34, 0xD4
1,1,0,0, 1,0,1,0, 1,0,1,1, 0,0,1,1, // 0xCA, 0xB3
0,0,1,0, 1,0,1,0, 1,1,0,1, 0,1,0,0, // 0x2A, 0xD4
1,0,1,0, 1,1,0,1, 0,1,0,1, 0,1,0,1, // 0xAD, 0x55
0,1,0,0, 1,0,1,0, 1,1,0,1, 0,0,1,1, // 0x4A, 0xD3
0,0,1,1, 0,1,0,1, 0,0,1,0, 1,1,0,0, // 0x35, 0x2C
1,1,0,1, 0,1,0,0, 1,1,0,0, 1,0,1 // 0xD4, 0xCA
};
short int call_F5OEO[239] = {1,0,1,1, 0,1,0,1, 0,0,1,0, 1,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,0, 1,1,0,1, 0,1,0,0, 1,1,0,0,
1,1,0,0, 1,1,0,0, 1,0,1,0, 1,1,0,1, 0,1,0,1, 0,0,1,0, 1,0,1,0, 1,1,0,1, 0,0,1,1, 0,1,0,0,
1,0,1,0, 1,0,1,1, 0,1,0,1, 0,1,0,1, 0,0,1,0, 1,0,1,0, 1,1,0,1, 0,0,1,1, 0,0,1,1, 0,0,1,0,
1,1,0,0, 1,1,0,1, 0,0,1,0, 1,1,0,1, 0,1,0,1, 0,1,0,0, 1,0,1,1, 0,1,0,0, 1,0,1,1, 0,0,1,1,
0,1,0,1, 0,0,1,1, 0,1,0,1 ,0,1,0,0, 1,0,1,0, 1,0,1,0, 1,1,0,1, 0,1,0,0, 1,1,0,1, 0,1,0,1,
0,0,1,0, 1,0,1,1, 0,0,1,0, 1,1,0,1 ,0,0,1,1, 0,1,0,1, 0,0,1,1, 0,1,0,0, 1,1,0,0, 1,0,1
};
short int call_7L1RLL[239] =
{
1,0,1,0, 1,1,0,1, 0,0,1,0, 1,1,0,1, // 0xAD, 0x2D
0,0,1,0, 1,0,1,0, 1,1,0,0, 1,0,1,0, // 0x2A, 0xCA
1,0,1,0, 1,0,1,0, 1,0,1,1, 0,1,0,0, // 0xAA, 0xB4
1,0,1,1, 0,0,1,0, 1,0,1,0, 1,0,1,1, // 0xB2, 0xAB
0,0,1,1, 0,1,0,1, 0,0,1,0, 1,0,1,0, // 0x35, 0x2A
1,0,1,0, 1,0,1,1, 0,1,0,1, 0,0,1,1, // 0xAB, 0x53
0,0,1,1, 0,0,1,0, 1,1,0,0, 1,1,0,0, // 0x32, 0xCC
1,1,0,1, 0,0,1,0, 1,0,1,0, 1,0,1,1, // 0xD2, 0xAB
0,0,1,1, 0,0,1,0, 1,1,0,0, 1,0,1,1, // 0x32, 0xCB
0,1,0,0, 1,1,0,0, 1,1,0,1, 0,1,0,1, // 0x4C, 0xD5
0,1,0,1, 0,0,1,1, 0,1,0,1, 0,0,1,1, // 0x53, 0x53
0,0,1,0, 1,1,0,0, 1,1,0,0, 1,1,0,1, // 0x2C, 0xCD
0,1,0,0, 1,1,0,1, 0,1,0,0, 1,0,1,1, // 0x4D, 0x4B
0,1,0,0, 1,1,0,0, 1,0,1,1, 0,1,0,0, // 0x4C, 0xB4
1,0,1,0, 1,0,1,0, 1,0,1,0, 1,1,0 // 0xAA, 0xAC
};
short int interleave_target[119] =
{ //after interleave
1,0,0,1, 1,0,1,1, 0,1,0,0, 1,0,1,1, //0x9B, 0x4B
1,1,0,1, 1,0,1,0, 0,1,1,1, 0,1,0,1, //0xDA, 0x75
0,1,0,0, 1,0,1,1, 1,1,1,0, 1,0,0,0, //0x4B, 0xE8
0,1,0,1, 0,0,0,1, 1,0,0,1, 1,1,0,0, //0x51, 0x9C
1,0,0,1, 0,0,0,1, 0,1,1,1, 1,0,1,0, //0x91, 0x7A
1,1,1,1, 0,0,0,1, 1,1,0,0, 0,0,0,0, //0xF1, 0xC0
0,1,1,1, 0,0,1,0, 1,0,0,0, 1,1,0,1, //0x72, 0x8D
0,0,0,1, 0,1,1 //0x16
};
short int before_interleave_target[119] =
{ // before interleave
1,1,0,1, 0,0,1,0, 0,0,0,0, 0,0,0,1, // 0xD2, 0x01
1,0,0,1, 1,1,1,0, 0,1,1,0, 1,0,1,1, // 0x9E, 0x6B
0,1,0,0, 1,1,1,1, 0,0,1,0, 1,0,1,0, // 0x4F, 0x2A
1,1,0,1, 0,1,0,1, 0,1,1,1, 1,0,0,1, // 0xD5, 0x79
1,0,1,0, 0,1,0,1, 1,1,1,0, 0,0,0,0, // 0xA5, 0xE0
0,0,0,0, 1,1,0,0, 1,1,0,0, 0,0,1,1, // 0x0C, 0xC3
1,1,1,1, 0,0,1,1, 0,1,0,1, 0,1,0,1, // 0xF3, 0x55
1,1,0,1, 0,0,1 // 0xD2
};
short int walsh_matrix[8][7] = {
{0,0,0,0,0,0,0},{1,0,1,0,1,0,1},{0,1,1,0,0,1,1},{1,1,0,0,1,1,0},
{0,0,0,1,1,1,1},{1,0,1,1,0,1,0},{0,1,1,1,1,0,0},{1,1,0,1,0,0,1}
};
short int pseudo_sequence[51] =
{
1,1,1,0, 0,0,0,1, 0,1,0,1, 0,1,1,1, // 0xE1, 0x57
1,1,1,0, 0,1,1,0, 1,1,0,1, 0,0,0,0, // 0xE6, 0xD0
0,0,0,1, 1,0,0,1, 0,0,0,1, 0,1,0,1, // 0x19, 0x15
0,1,1 // 0x60
};
char before_scramble_target[52] =
"000000000110110001101111000011110001111000001100100";
short int before_WH_target[52] =
{
1,1,1,0, 0,0,0,1, 0,0,1,1, 1,0,1,1, // 0xE1, 0x3B
1,0,0,0, 1,0,0,1, 1,1,0,1, 1,1,1,1, // 0x89, 0xDF
0,0,0,0, 0,1,1,1, 0,0,0,1, 1,0,0,1, // 0x07, 0x19
1,1,1 // 0xE0
};
char packed_target[29] ="0000011011000110111100001111"; //0x0606F0F
char call_target[7] = "AA1AA ";
// **** Grobal variables ****
short int symbol[239]; // to be decode
short int interleaved[119];
short int before_interleave[119];
short int error_position[239]; // does not use in V1.0.0
short int before_WH[51];
char before_scramble[51];
char packed[28];
char call[7];
short int DEBUG = 0;
// **** functions ****
void decode_opera(short int symbol[239]);
void manchester_decode(short int symbol[239], short int interleaved[119]);
void de_interleave(short int interleaved[119], short int before_interleave[119]);
void de_walsh_matrix(short int before_interleave[119], short int before_WH[51]);
void de_scramble(short int befor_WH[51], char before_scramble[51]);
void de_crc(char before_scramble[51], char packed[28]);
void generate_crc(char datas[28], char crc[17], int length);
void unpack(char packed[28], char call[7]);
char de_normalizer(int bc, int byte_num);
void print_help();
void print_short_int(const char* caption, short int* code, int length);
void print_str(const char* caption, char* code);
void strcpy_w(char * s1, char * s2, int length);
void strcat_w(char * s1, char * s2, int lenS1, int lenS2);
//**********************************
int main(int argc, char* argv[])
//**********************************
{
char s1 = 0x00;
int i;
printf("argc=%d\n", argc);
switch(argc)
{
case 1 : // Help required
{
printf("%s\n","More argument is required !");
print_help();
return 0;
}
case 2 : // 2 arguments
{
s1 = (char) argv[1][0];
if ((s1 == '?') && (argv[1][1] == 0x00))
{
printf("%s\n", "Help selected");
print_help();
return 0;
}
else if ((s1 == 'd' || s1 == 's' || s1 == 'w') && (argv[1][1] == 0x00))
{
if (s1 =='d')
{
printf("%s\n", "Debug selected.");
DEBUG = 1;
for (i = 0; i < 239; i++)
symbol[i] = call_AA1AA[i];
decode_opera(symbol);
DEBUG = 0;
return 0;
}
else if (s1 == 's')
{
printf("%s\n", "Sample selected.");
for (i = 0; i < 239; i++)
symbol[i] = call_F5OEO[i];
decode_opera(symbol);
DEBUG = 0;
return 0;
}
else
{
printf("%s\n", "Sample 7L1RLL selected.");
DEBUG = 0;
for (i = 0; i < 239; i++)
symbol[i] = call_7L1RLL[i];
decode_opera(symbol);
DEBUG = 0;
return 0;
}
}
}
default : // 3 arguments
{
printf("%s\n", "Too many arguments.");
print_help();
return 0;
}
}
} // end of _tmain()
//**************************************************
void decode_opera(short int * symbol)
//**************************************************
{
print_short_int("symbol given =", symbol, 239);
manchester_decode(symbol, interleaved);
print_short_int("de_manchester code =", interleaved, 119);
if (DEBUG)
print_short_int("de_manchester_target =", interleave_target, 119);
de_interleave(interleaved, before_interleave);
print_short_int("de_interleave =", before_interleave, 119);
if (DEBUG)
print_short_int("de_interleave_target =", before_interleave_target, 119);
de_walsh_matrix(before_interleave, before_WH);
print_short_int("de_Walsh-Hamadard =", before_WH, 51);
if (DEBUG)
print_short_int("de_WH_target =", before_WH_target, 51);
de_scramble(before_WH, before_scramble);
print_str("de_scramble = ", before_scramble);
if (DEBUG)
print_str("de_scramble_target = ", before_scramble_target);
de_crc(before_scramble, packed);
print_str("de_CRC = ", packed);
if (DEBUG)
print_str("de_CRC_target = ", packed_target);
unpack(packed, call);
printf("unpached call = %s\n", call);
if (DEBUG)
printf("call_target = %s\n", call_target);
} // end of decode_opera()
//***********************************************************************
void manchester_decode(short int* symbol, short int* symbol_interleaving)
//***********************************************************************
{
int i = 0;
int idx = 0; // delete start 2 bit
while (idx < 238)
{
if ((symbol[idx + 1] == 1) && (symbol[idx + 2] == 0))
{
symbol_interleaving[i] = (short) 0;
}
else if ((symbol[idx + 1] == 0) && (symbol[idx + 2] == 1))
{
symbol_interleaving[i] = (short) 1;
}
else
{
error_position[idx] = (short) 1;
}
i++; idx += 2;
}
} // end of manchester_decode()
//************************************************************************
void de_interleave(short int* interleaved, short int* before_interleave)
//************************************************************************
{
int i =0, idx = 0, j = 0;
for (i = 0; i < 7; i++)
{
for (j = i; j < 119; j += 7)
{
before_interleave[j] = interleaved[idx];
idx++;
}
}
} // end of de_interleave
//*********************************************************************
void de_walsh_matrix(short int* vector_to_tx, short int* symbol_coding)
//*********************************************************************
{ // 119 bit to 51 bit
int idx = 0, i, j, k, data = 0;
short int temp[7];
for (i = 0; i < 119; i += 7)
{
for(j = 0; j < 7; j++) temp[j] = vector_to_tx[i + j];
temp[7]=0x00;
// search the value for match
data = 0;
for (k = 0; k < 7; k++)
{
if (k < 6)
{
data = data + (int) pow((double)(temp[k]*2), (6 - k));
}
else if (k == 6)
{
if (temp[6] == 1) data = data + 1;
}
}
if (data == 0) // 0000000 = 0
{
symbol_coding[idx + 0] = 0;
symbol_coding[idx + 1] = 0;
symbol_coding[idx + 2] = 0;
}
else if (data == 85) // 1010101 = 2^6 + 2^4 + 2^2 + 1 = 85
{
symbol_coding[idx + 0] = 0;
symbol_coding[idx + 1] = 0;
symbol_coding[idx + 2] = 1;
}
else if (data == 51) // 0110011 = 2^5 + 2^4 + 2 + 1 = 51
{
symbol_coding[idx + 0] = 0;
symbol_coding[idx + 1] = 1;
symbol_coding[idx + 2] = 0;
}
else if (data == 102) // 1100110 = 2^6 + 2^5 + 2^2 + 2 = 102
{
symbol_coding[idx + 0] = 0;
symbol_coding[idx + 1] = 1;
symbol_coding[idx + 2] = 1;
}
else if (data == 15) // 0001111 = 2^3 + 2^2 + 2 + 1 = 15
{
symbol_coding[idx + 0] = 1;
symbol_coding[idx + 1] = 0;
symbol_coding[idx + 2] = 0;
}
else if (data == 90) // 1011010 = 2^6 + 2^4 + 2^3 + 2 = 90
{
symbol_coding[idx + 0] = 1;
symbol_coding[idx + 1] = 0;
symbol_coding[idx + 2] = 1;
}
else if (data == 60) //0111100 = 2^5 + 2^4 + 2^3 + 2^2 = 60
{
symbol_coding[idx + 0] = 1;
symbol_coding[idx + 1] = 1;
symbol_coding[idx + 2] = 0;
}
else if (data == 105) // 1101001 = 2^6 + 2^5 + 2^3 + 1 = 105
{
symbol_coding[idx + 0] = 1;
symbol_coding[idx + 1] = 1;
symbol_coding[idx + 2] = 1;
}
else printf("xxxx");
idx +=3;
}
} // enf of de-WH
//************************************************************
void de_scramble(short int * vector_to_tx, char * vector)
//************************************************************
{ // | 51 bit | to | 51 bit |
short int vector_temp[51];
int i;
// convert binary to ASCII
for (i = 0; i < 51; i++)
{
vector_temp[i] = vector_to_tx[i] ^ pseudo_sequence[i];
vector[i] = (char) vector_temp[i] + 0x30;
}
} //end of de_scramble()
//*************************************************
void de_crc(char * vector, char * packed)
//*************************************************
{ // 51 bits to 28bits
char crc1[17], crc1a[17], crc2[4], crc2a[4];
int i, crc_ok;
char temp[52] = {0};
// extract packed from received data
for (i = 0; i < 28; i++) //4..31 for packed
packed[i] = temp[i] = vector[i + 4];
packed[28] = temp[28] = 0x00;
if (DEBUG)
print_str("temp in de_crc = ", temp);
if (DEBUG)
print_str("packed in de_crc = ", packed);
// extract crc1 from received data
for (i = 0; i < 16; i++) //32..47 for crc1
crc1[i] = vector[i + 32];
crc1[16] = 0x00;
if (DEBUG)
print_str("crc1 exracted from received data = ", crc1);
//crc2 extracted from received data
for (i = 0; i < 3; i++) //48..50 for crc2
crc2[i] = vector[i + 48];
crc2[3] = 0x00;
if (DEBUG)
print_str("crc2 extracted from received data = ", crc2);
generate_crc(temp, crc1a, 16);
if (DEBUG)
print_str("temp before crc add = ", temp);
if (DEBUG)
print_str("crc1a calcurated = ", crc1a);
strcat_w(temp, crc1a, 28, 16); // 28 + 16 = 44
generate_crc(temp, crc2a, 3);
strcat_w(temp, crc2a, 44, 3); // 44 + 3 = 47
// verify crc1 and crc2
crc_ok = 1;
for (i = 0; i < 16; i++)
if (crc1[i] != crc1a[i]) crc_ok = 0;
for (i = 0; i < 3; i++)
if (crc2[i] != crc2a[i]) crc_ok = 0;
if (crc_ok)
printf("CRC : OK\n");
else
{
printf("CRC : No good\n");
print_str("crc1a calcurated = ", crc1a);
print_str("crc1_received = ", crc1);
print_str("crc2a calcurated = ", crc2a);
print_str("crc2a_received = ", crc2);
}
} //end of de_crc()
//************************************************************************
void generate_crc(char * datas, char * crc, int length)
//************************************************************************
{ // 32 + 16(length) = 48 or 48 + 3(length) = 51
// CRC16-IBM : Polynominal = X16+X15+X2+1 = 1000 0000 0000 0101
// This function is a copy of JUMA TX136/500 control program
// whitch was written by F4GCB (Patrick). Thanks Patrick.
int i, j, k, len;
char buffer[52];
short int wcrc[17] = {0}, byte1 = 0, byte2 = 0;
len = strlen(datas);
for (i = 0; i < len; i++)
buffer[i] = datas[i];
buffer[len] = 0x00;
if (DEBUG)
print_str("input datas in generate_crc =", buffer);
for (i = 0; i < len; i++)
{
for (j = 0; j < 8; j++)
{
if (j > 0) buffer[i] = buffer[i] >> 1;
byte1 = buffer[i] & 0x01;
byte2 = byte1 ^ wcrc[0]; // XOR with X16
wcrc[0] = byte2 ^ wcrc[1]; // XOR with X15
for (k = 1; k < 13; k++)
wcrc[k] = wcrc[k + 1];
wcrc[13] = byte2 ^ wcrc[14]; // XOR with X2
wcrc[14] = wcrc[15]; //
wcrc[15] = byte2; //
}
}
// if msb byte crc = 0 then value at 27
byte2 = 0;
for (i = 0; i < 8; i++)
byte2 = byte2 + (int)(wcrc[i] * pow (2.0, i));
if (byte2 == 0) byte2 = 27; // 0x1B = 0b0001 1011
// if lsb byte crc = 0 then value at 43
byte1 = 0;
for (i = 8; i < 16; i++)
byte1 = byte1 + (int)(wcrc[i] * pow(2.0, i - 8));
if (byte1 == 0) byte1 = 43; // 0x2B = 0b0010 1011
if (DEBUG)
printf("byte1 before replace =%2x, byte2 =%2x\n", byte1, byte2);
// merge crc into a bit string
for (i = 0; i < 8; i++)
{
if (i > 0) byte2 = byte2 >> 1;
wcrc[7 - i] = byte2 & 0x01; // (binary)
if (i > 0) byte1 = byte1 >> 1;
wcrc[15 - i] = byte1 & 0x01; // (binary)
}
if (length > 16) length = 16;
for (i = 16 - length; i < 16; i++)
crc[i - (16 - length)] = wcrc[i] + 0x30;
crc[length]= 0x00;
if (DEBUG)
print_str("crc =", crc);
} // end of generate_crc()
//*************************************
void unpack(char * packed, char * call)
//*************************************
{ // 28 bits to 48 bits
int i;
int temp;
unsigned long code_sum = 0, remains = 0;
if (DEBUG)
print_str("packed in unpack = ", packed);
// separate a string to coded callsign
for (i = 0; i < 28; i++)
code_sum = code_sum + (unsigned long)(packed[27 - i] - '0') * pow(2.0, i);
// de_normalizer of callsign
remains = 36*10*27*27*27;
if (DEBUG)
{
printf(" 0 : code_sum = %9Lu\n", code_sum);
printf(" 0 : remains = %9Lu\n", remains);
}
if (code_sum > remains)
{
temp = code_sum / remains;
code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 0 : temp = %9Lu\n", temp);
call[0] = de_normalizer(temp, 0);
remains = 10*27*27*27;
if (DEBUG)
{
printf(" 1 : code_sum = %9Lu\n", code_sum);
printf(" 1 : remains = %9Lu\n", remains);
}
if (code_sum >= remains)
{
temp = code_sum / remains;
code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 1 : temp = %9Lu\n", temp);
call[1] = de_normalizer(temp, 1);
remains = 27*27*27;
if (DEBUG)
{
printf(" 2 : code_sum = %9Lu\n", code_sum);
printf(" 2 : remains = %9Lu\n", remains);
}
if (code_sum >= remains)
{
temp = code_sum / remains;
code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 2 : temp = %9Lu\n", temp);
call[2] = de_normalizer(temp, 2);
remains = 27*27;
if (DEBUG)
{
printf(" 3 : code_sum = %9Lu\n", code_sum);
printf(" 3 : remains = %9Lu\n", remains);
}
if (code_sum >= remains)
{
temp = code_sum / remains;
code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 3 : temp = %9Lu\n", temp);
call[3] = de_normalizer(temp, 3);
remains = 27;
if (DEBUG)
{
printf(" 4 : code_sum = %9Lu\n", code_sum);
printf(" 4 : remains = %9Lu\n", remains);
}
if (code_sum >= remains)
{
temp = code_sum / remains;
code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 4 : temp = %9Lu\n", temp);
call[4] = de_normalizer(temp, 4);
remains = 1;
if (DEBUG)
{
printf(" 5 : code_sum = %9Lu\n", code_sum);
printf(" 5 : remains = %9Lu\n", remains);
}
if (code_sum >= remains)
{
temp = code_sum;
//code_sum %= remains;
}
else temp = 0;
if (DEBUG)
printf(" 5 : temp = %9Lu\n", temp);
call[5] = de_normalizer(temp, 5);
call[6] = 0x00;
} // end of unpack
//********************************
char de_normalizer(int bc, int n)
//********************************
{
char cc = 0;
if (DEBUG)
printf(" %u : input of de_normalizer, bc = %9Lu\n", n, bc);
switch (n)
{
case 0 :
{
if (bc == 0) cc = ' ';
else if (bc >= 1 && bc <= 26) cc = bc - 1 +'A';
else if (bc >= 27 && bc <= 37) cc = bc - 27 + '0';
break;
}
case 1 :
{
if (bc >= 0 && bc <= 25) cc = bc + 'A';
else if (bc >= 26 && bc <= 36) cc = bc - 26 + '0';
break;
}
case 2 :
{
if (bc >= 0 && bc <= 9) cc = bc + '0';
break;
}
case 3: case 4: case 5:
{
if (bc == 0) cc = ' ';
else if (bc >= 1 && bc <= 26) cc = bc - 1 + 'A';
break;
}
default : break;
}
if (DEBUG)
printf(" %u : output of de_normalizer, cc = %c\n", n, cc);
return (cc);
} // end of de _normlizer
//********************************************************************
void print_short_int(const char *caption, short int *code, int length)
//********************************************************************
{ // This is a service function for debugging
int i = 0;
printf("%s\n", caption);
for (i = 0; i < length; i++)
{
printf("%u", code[i]);
if (((i + 1) % 4) == 0) printf(" ");
if (((i + 1) % 40) == 0) printf("\n");
}
printf("\n");
} // end fo print_short_int
//********************************************************************
void print_short_char(const char * caption, char * code, int length)
//********************************************************************
{ // This is a service function for debugging
int i = 0;
printf("%s\n", caption);
for (i = 0; i < length; i++)
{
printf("%c", code[i]);
if (((i + 1) % 4) == 0) printf(" ");
if (((i + 1) % 40) == 0) printf("\n");
}
printf("\n");
} // end fo print_short_char
//********************************************************************
void print_str(const char * caption, char * code)
//********************************************************************
{ // This is a service function for debugging
int i = 0;
printf("%s\n", caption);
for (i = 0; i < strlen(code); i++)
{
printf("%c", code[i]);
if (((i + 1) % 4) == 0) printf(" ");
if (((i + 1) % 40) == 0) printf("\n");
}
printf("\n");
} // end fo print_char
//*******************************************************
void strcpy_w(char * s1, char * s2, int length)
//*******************************************************
{
int i;
for (i = 0; i < length; i++)
s1[i] = s2[i];
s1[length] = 0x00;
} // end of strcpy_w
//****************************************************************
void strcat_w(char * s1, char * s2, int lenS1, int lenS2)
//****************************************************************
{
int i;
for (i = 0; i < lenS2; i++)
s1[i + lenS1] = s2[i];
s1[lenS1 + lenS2]= 0x00;
} // end of strcat_w()
//***************
void print_help()
//***************
{
printf("%s\n","Usage : OPERA_Decode_Test [ ? | d | s | w]");
printf("%s\n"," Help : OPERA_Decode_Test ?");
printf("%s\n"," Debug : OPERA_Decode_Test d");
printf("%s\n"," AA1AA : OPERA_Decode_Test s");
printf("%s\n"," 7L1RLL : OPERA_Decode_Test w");
printf("%s\n"," Sample callsign is \"AA1AA\". ");
} // end of help
//************** End of Program **************************************

View File

@@ -1,515 +0,0 @@
//******************************************************************************
// OPERA_Coding_Test.cpp : Defines the entry point for the console application.
//
// Purpose : Algorithm testing by a laptop computer before implementation
// into PIC micro processor.
//
// Usage: "OPERA_Coding_Test [? | d | s] ["callsign"]";
// where : s = help, d = debug and s = sample";
//
// Version 1.0.4, 2015/11/29: Modified print format
// Version 1.0.3, 2015/11/13: Delete an additional start bit for decoder
// Version 1.0.2, 2015/11/11: Add Visual C++ directives
// Version 1.0.1, 2015/11/10: Changed help message
// Version 1.0.0, 2015/11/07: Initial Release
//
// Copyright(C) 2015 F4GCB
// Partial copyright (C)2015 7L1RLL
// Partial copyright (C)2017 F5OEO Add output format to Rpitx RFA Mode
//
// Acknowledgement :
// 1)Portion of this OPERA is derived from the work of EA5HVK.
// 2)All functions of this program are a copy of JUMA-TX500/136
// Transmitter Controller which written by F4GCB.
//******************************************************************************
//#include "stdafx.h"
//#include <locale.h>
//#include <tchar.h>
#include "stdio.h"
#include "string.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdint.h"
#include "math.h"
//#define __VCpp__ TRUE
// Grobal Variables
int FileFreqTiming;
// Test program using SNDFILE
// see http://www.mega-nerd.com/libsndfile/api.html for API
void WriteTone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=Frequency;
RfSample.WaitForThisSample=Timing; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming,&RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample\n");
}
}
static const short int pseudo_sequence[51] = {
1,1,1,0,0,0,0,1,0,1, 0,1,0,1,1,1,1,1,1,0, 0,1,1,0,1,1,0,1,0,0, 0,0,0,0,0,1,1,0,0,1,
0,0,0,1,0,1,0,1,0,1, 1
};
static short int walsh_matrix[8][7] = {
{0,0,0,0,0,0,0},{1,0,1,0,1,0,1},{0,1,1,0,0,1,1},{1,1,0,0,1,1,0},
{0,0,0,1,1,1,1},{1,0,1,1,0,1,0},{0,1,1,1,1,0,0},{1,1,0,1,0,0,1}
};
static short int symbol[239];
char call[7], call_coded[45], vector[52];
short int vector_to_tx[51];
short int symbol_interleaving[119], symbol_coding[119];
short int DEBUG = 0;
const char sampleCall[7] = "AA1AA";
// Declaration of functions
void genn_opera(float mode);
void generate_call(char call[7], char call_coded[45]);
void add_crc16(char call_coded[45], char vector[52]);
void scramble(char vector[52], short int symbol_coding[119]);
void Walsh_Hammered_code(short int symbol_coding[119], short int vector_to_tx[51]);
void interleave(short int vector_to_tx[51], short int symbol_interleaving[119]);
void ManchesterEncode(short int symbol_interleaving[119], short int symbol[239]);
char chr_norm_opera(char bc);
void print_short_int(const char caption[], short int code[239], int length);
void print_str(const char caption[250], char code[52]);
void strcpy_w(char s1[52], char s2[52], int length);
void strcat_w(char s1[52], char s2[52], int lenS1, int lenS2);
void encodepitx(short int *code, int length,float Nop);
#ifdef __VCpp__
//**********************************
// main forVisual C++
int _tmain(int argc, _TCHAR* argv[])
//**********************************
{
_tsetlocale(LC_ALL, _T("")); //Change Unicode to OS-Default locale
#else
int main(int argc, char* argv[])
//**********************************
{
#endif
int i = 0;
char s1 = 0x00, s2[7] = "";
switch (argc)
{
case 1 : // Help required
case 2 : // Help required
case 3 : // Help required
{
printf("Usage : %s CALLSIGN OperaMode[0.5,1,2,4,8} file.rfa \n", argv[0]);
return 0;
}
case 4: // 3 arguments
{
s1 = (char)argv[1][0];
// range check
if (!((argv[1][0] >= '0' && argv[1][0] <= '9') || (argv[1][0] >= 'A' && argv[1][0] <= 'Z') ||
(argv[1][0] >= 'a' && argv[1][0] <= 'z')))
{
printf("%s\n","Callsign must be began with an alphan/numeric character");
return 0;
}
DEBUG = 0; i = 0;
while (argv[1][i] != 0 && i < 7)
{
call[i] = argv[1][i]; call[++i] = 0x00;
}
float Mode=atof(argv[2]);
FileFreqTiming = open( argv[3], O_WRONLY|O_CREAT, 0644);
genn_opera(Mode);
return 0;
}
default:
{
printf("Usage : %s CALLSIGN OperaMode[0.5,1,2,4,8} file.rfa \n", argv[0]);
break;
}
} // end of switch argc
return 0;
} // end of _tmain
//*******************
void genn_opera(float mode)
//*******************
{
printf("\nGenerate Op%.1f Callsign = %s\n",mode,call);
generate_call(call, call_coded);
if (DEBUG)
print_str("call_coded =", call_coded);
add_crc16(call_coded, vector);
if (DEBUG)
print_str("crc16 vector =", vector);
scramble(vector, vector_to_tx);
if (DEBUG)
print_short_int("vector_to_tx =", vector_to_tx, 44);
Walsh_Hammered_code(vector_to_tx, symbol_coding);
if (DEBUG)
print_short_int("symbol_coding =", symbol_coding, 119);
interleave(symbol_coding, symbol_interleaving);
if (DEBUG)
print_short_int("symbol_interleaving =", symbol_interleaving, 119);
ManchesterEncode(symbol_interleaving, symbol);
//print_short_int("symbol =", symbol, 239);
encodepitx(symbol,239,mode);
} // genn_opera
//****************************************************
// Normalize characters space S..Z 0..9 in order 0..36
char chr_norm_opera(char bc)
//****************************************************
{
char cc = 0;
if (bc >= '0' && bc <= '9') cc = bc - '0' + 27;
if (bc >= 'A' && bc <= 'Z') cc = bc - 'A' + 1;
if (bc >= 'a' && bc <= 'z') cc = bc - 'a' + 1;
if (bc == ' ') cc = 0;
return (cc);
} // enf of chr_norm_opera
//**********************************************
void generate_call(char *call, char *call_coded)
//**********************************************
{
int i;
unsigned long code_sum;
//the thired character must always be a number
if (chr_norm_opera(call[2]) < 27)
{
for (i=5; i> 0; i--) call[i] = call[i-1];
call[0]=' ';
}
// the call must always have 6 characters
for (i=strlen(call); i < 6; i++)
call[i] = ' ';
call[6] = 0x00;
if (DEBUG) printf("NormalizedCall=%s\n", call);
code_sum = chr_norm_opera(call[0]);
code_sum = code_sum * 36 + chr_norm_opera(call[1]) - 1;
code_sum = code_sum * 10 + chr_norm_opera(call[2]) - 27;
code_sum = code_sum * 27 + chr_norm_opera(call[3]);
code_sum = code_sum * 27 + chr_norm_opera(call[4]);
code_sum = code_sum * 27 + chr_norm_opera(call[5]);
if (DEBUG) printf("code_sum=%Lu\n", code_sum);
// merge coded callsign ino a string
call_coded[28] = 0x00;
call_coded[27] = (short int) ((code_sum & 0x01) + 0x30);
for (i = 26; i >= 0; i--)
{
code_sum = code_sum >> 1;
call_coded[i] = (short int)((code_sum & 0x01) + 0x30);
}
} // end of pack_callsign
//***************************************************
void generate_crc(char *datas, char *crc, int length)
//***************************************************
{
unsigned int i, j, k;
char buffer[52]; //strlen(datas)];
short int wcrc[16] = {0}, byte1 = 0, byte2 = 0;
#ifdef __VCpp__
strcpy_s(buffer, 52, datas);// strcpy(buffer, datas);
#else
strcpy(buffer, datas);// strcpy(buffer, datas);
#endif
if (DEBUG)
print_str("buffer_crc = ", buffer);
for (i = 0; i < strlen(datas); i++)
{
for (j = 0; j < 8; j++)
{
if (j > 0) buffer[i] = buffer[i] >> 1;
byte1 = buffer[i] & 0x01;
byte2 = byte1 ^ wcrc[0];
wcrc[0] = byte2 ^ wcrc[1];
for (k = 1; k < 13; k++)
wcrc[k] = wcrc[k+1];
wcrc[13] = byte2 ^ wcrc[14];
wcrc[14] = wcrc[15];
wcrc[15] = byte2;
}
}
// if msb byte crc = 0 then value at 27
byte2 = 0;
for (i = 0; i < 8; i++)
#ifdef __VCpp__ // add for Visual C++ by 7L1RLL 11/07/2015
byte2 = byte2 + (short) wcrc[i] * pow((double)2.0, (int)i);
#else
byte2 = byte2 + wcrc[i] * pow(2, i);
#endif
if (byte2 == 0) byte2 =27;
// if lsb byte crc = 0 then value at 43
byte1 = 0;
for (i = 8; i < 16; i++)
#ifdef __VCpp__
byte1 = byte1 + (short) (wcrc[i] * (double)pow(2.0, (int)i - 8)); // add cast by 7L1RLL
#else
byte1 = byte1 + (wcrc[i] * pow(2, i - 8));
#endif
if (byte1 == 0) byte1 = 43;
if (DEBUG) printf("byte1 = %x, byte2 = %x\n", byte1, byte2);
// merge crc into a string
for (i = 0; i < 8; i++)
{
if (i > 0) byte2 = byte2 >> 1;
wcrc[7 - i] = byte2 & 0x01;
if ( i > 0) byte1 = byte1 >> 1;
wcrc[15 - i] = byte1 & 0x01;
}
if (length > 16) length = 16;
for (i = 16 - length; i < 16; i++)
crc[i - (16 - length)] = wcrc[i] + 0x30;
crc[length] = 0x00;
} // end of genarate_crc
//*********************************************
void add_crc16(char * call_coded, char *vector)
//*********************************************
{ // input: |28 bits|, output : |51 bits|
char crc1[17] = "", crc2[4] = "";
#ifdef __VCpp__ // for wide character compiler
char temp[52] = "";
_tsetlocale(LC_ALL, _T("")); //Change Unicode to OS-Default locale
if (DEBUG)
print_str("call_coded in add CRC16 =", call_coded);
strcpy_w(temp, call_coded, 28); // 28 bit
if (DEBUG)
print_str("temp in add CRC16=", temp);
generate_crc(call_coded, crc1, 16);
if (DEBUG)
print_str("crc1 =", crc1);
strcat_w(temp, crc1, 28, 16); // 28 + 16 = 44
generate_crc( temp, crc2, 3);
if (DEBUG)
print_str("crc2 =", crc2);
#else // PIC C compiler using ASCII
// char crc1[17] = "", crc2[4] = "";
generate_crc(call_coded, crc1, 16);
if (DEBUG) printf("crc1 =%s\n", crc1);
generate_crc(strcat(call_coded, crc1), crc2, 3);
if (DEBUG) printf("crc2 =%s\n", crc2);
#endif
// |4 bits sync| + |28 bits call| + |19 bit crc|
#ifdef __VCpp__
strcpy_w(vector, "0000", 4); // 4
strcat_w(vector, temp, 4, 44); // 4 + 44 = 48
strcat_w(vector, crc2, 48, 3); // 48 + 3 = 51
#else // not VC++ ex : PIC
strcpy(vector, "0000"); // 4
strcat(vector, call_coded); // 4 + 44 = 48
strcat(vector, crc2); // 48 + 3 = 51
#endif
} // end of add_crc16
//**************************************************
void scramble(char *vector, short int *vector_to_tx)
//**************************************************
{ // encoding |51 bits|
int i=0;
for (i = 0; i < 51; i++)
{
vector_to_tx[i] = vector[i] & 0x01;
// convert ASCII to binary
vector_to_tx[i] = vector_to_tx[i] ^ pseudo_sequence[i];
}
} // end of scrambling
//*************************************************************************
void Walsh_Hammered_code(short int *vector_to_tx, short int *symbol_coding)
//*************************************************************************
{ // order 8 walsh matrix codification : |119 bits|
int data = 0, idx = 0, i = 0, j = 0;
for (i = 0; i < 51; i += 3)
{
data = 0;
for (j = 0; j < 3; j++)
data = data + (vector_to_tx[i + j] << (2 - j));
for (j = 0; j < 7; j++)
{
symbol_coding[idx] = walsh_matrix[data][j];
idx++;
}
}
} //end of Walsh_Hammered_code
//***********************************************************************
void interleave(short int *symbol_coding, short int *symbol_interleaving)
//***********************************************************************
{ // interleaving : |119 bits|
int idx = 0, i = 0, j = 0;
idx = 0;
for (i = 0; i < 7; i++)
{
for (j = i; j < 119; j += 7)
{
symbol_interleaving[idx]= symbol_coding[j];
idx++;
}
}
} // end of interleave
//**********************************************************************
void ManchesterEncode(short int *symbol_interleaving, short int *symbol)
//**********************************************************************
{ // manchester codification : |11| + |238 bits| - |1 bit| modified by 7L1RLL 11/07/2015
int idx = 0;
int i = 0, j = 0;
symbol[0] = 1;
for (i = 0; i < 119; i++)
{
if (symbol_interleaving[i] == 0)
{
symbol[idx + 1] = 1;
symbol[idx + 2] = 0;
}
else
{
symbol[idx + 1] = 0;
symbol[idx + 2] = 1;
}
idx += 2;
}
} // end of Manchester_encode
//***************
void print_help()
//***************
{
printf("%s\n","Usage : OPERA_Coding_Test [? | s | [d \"callsign\"]]");
printf("%s\n"," Normal : OPERA_Coding_Test \"callsign\"");
printf("%s\n"," Help : OPERA_Coding_Test ?");
printf("%s\n"," Sample : OPERA_Coding_Test s");
printf("%s\n"," Debug : OPERA_Coding_Test d \"callsign\"");
printf("%s\n"," Callsign format shall be like \"AA1AAA\". ");
printf("%s\n"," Third character mast be a numeric character(0..9).");
} // end of help
//********************************************************************
void print_short_int(const char *caption, short int *code, int length)
//********************************************************************
{ // This is service function for debugging
int i = 0;
printf("%s\n", caption);
for (i = 0; i < length; i++)
{
printf("%d", code[i]);
if (((i+1) % 4) == 0) printf(" ");
if (((i+1) % 40) == 0) printf("\n");
}
printf("\n");
} // end fo print_short_int
void encodepitx(short int *code, int length,float Nop)
{
int i = 0;
int j=0;
/*and each of the
239 symbols are transmitted by keying the transmitter as CW on and off with a symbol
rate of 0.256*n s/symbol, where n is the integer of operation mode OPn that corresponds
with the Opera frequency recommendation: */
//WriteTone(1*32767,1e6*(256*Nop));
WriteTone(1*32767,1e6*(256*Nop));
for (i = 0; i < length-1; i++)
{
//for(j=0;j<1000;j++)
WriteTone(code[i]*32767,1e6*(256*Nop)); //AM
//WriteTone(code[i]*100000,1e6*(256*Nop)); //FM
}
}
//********************************************************************
void print_str(const char * caption, char * code)
//********************************************************************
{ // This is a service function for debugging
int i = 0;
printf("%s\n", caption);
for (i = 0; i < strlen(code); i++)
{
printf("%c", code[i]);
if (((i + 1) % 4) == 0) printf(" ");
if (((i + 1) % 40) == 0) printf("\n");
}
printf("\n");
} // end fo print_str
//*******************************************************
void strcpy_w(char * s1, char * s2, int length)
//*******************************************************
{
int i;
for (i = 0; i < length; i++)
s1[i] = s2[i];
s1[length] = 0x00;
} // end of strcpy_w
//****************************************************************
void strcat_w(char * s1, char * s2, int lenS1, int lenS2)
//****************************************************************
{
int i;
for (i = 0; i < lenS2; i++)
s1[i + lenS1] = s2[i];
s1[lenS1 + lenS2]= 0x00;
} // end of strcat_w()
//************** End of Program ********************************

View File

@@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Andrew Duncan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,80 +0,0 @@
#all: ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 ../piopera
all: librpitx v2rpitx ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 ../piopera
#CFLAGS = -Wall -g -O2 -D DIGITHIN
CFLAGS = -Wall -g -O2 -Wno-unused-variable
LDFLAGS = -lm -lrt -lpthread
../rpitx: RpiGpio.c RpiTx.c mailbox.c RpiDma.c raspberry_pi_revision.c calibrationpi2.h calibrationpizero.h calibrationpi3.h
$(CC) $(CFLAGS) -o ../rpitx RpiTx.c RpiGpio.c mailbox.c RpiDma.c raspberry_pi_revision.c $(LDFLAGS)
CFLAGS = -Wall -g -O3 -Wno-unused-variable
LDFLAGS = -lm -lrt -lpthread -lliquid
CCP = g++
CC = gcc
librpitx: librpitx.h gpio.h gpio.cpp dma.h dma.cpp mailbox.c raspberry_pi_revision.c fmdmasync.h fmdmasync.cpp ngfmdmasync.h ngfmdmasync.cpp dsp.h dsp.cpp iqdmasync.h iqdmasync.cpp serialdmasync.h serialdmasync.cpp phasedmasync.h phasedmasync.cpp fskburst.h fskburst.cpp
$(CC) $(CFLAGS) -c -o mailbox.o mailbox.c
$(CC) $(CFLAGS) -c -o raspberry_pi_revision.o raspberry_pi_revision.c
$(CCP) $(CFLAGS) -c dsp.cpp iqdmasync.cpp ngfmdmasync.cpp fmdmasync.cpp dma.cpp gpio.cpp mailbox.o raspberry_pi_revision.o v2rpitx.cpp serialdmasync.cpp phasedmasync.cpp amdmasync.h amdmasync.cpp fskburst.cpp
$(AR) rc librpitx.a dsp.o iqdmasync.o ngfmdmasync.o fmdmasync.o dma.o gpio.o mailbox.o raspberry_pi_revision.o serialdmasync.o phasedmasync.o amdmasync.o fskburst.o
v2rpitx: librpitx.h librpitx.a
$(CCP) $(CFLAGS) -o v2rpitx v2rpitx.cpp librpitx.a $(LDFLAGS)
CFLAGS_Pissb = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pissb = -lm -lrt -lpthread -lsndfile
../pissb: ../ssbgen/test_ssb.c ../ssbgen/ssb_gen.c
$(CC) $(CFLAGS_Pissb) -o ../pissb ../ssbgen/ssb_gen.c ../ssbgen/test_ssb.c $(LDFLAGS_Pissb)
CFLAGS_Pisstv = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pisstv = -lm -lrt -lpthread
../pisstv : ../sstv/v2pisstv.cpp
$(CCP) $(CFLAGS_Pisstv) -o ../pisstv ../sstv/v2pisstv.cpp ../src/librpitx.a $(LDFLAGS_Pisstv)
CFLAGS_Pifsq = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pifsq = -lm -lrt -lpthread
../pifsq : ../fsq/pifsq.c
$(CC) $(CFLAGS_Pisfq) -o ../pifsq ../fsq/pifsq.c $(LDFLAGS_Pisfq)
CFLAGS_Pifm = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pifm = -lm -lrt -lpthread -lsndfile
../pifm : ../fm/pifm.c
$(CC) $(CFLAGS_Pifm) -o ../pifm ../fm/pifm.c $(LDFLAGS_Pifm)
CFLAGS_Piam = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Piam = -lm -lrt -lpthread -lsndfile
../piam : ../am/piam.c
$(CC) $(CFLAGS_Piam) -o ../piam ../am/piam.c $(LDFLAGS_Piam)
CFLAGS_Pidcf77 = -Wall -g -O2 -Wno-unused-variable
LDFLAGS_Pidcf77 = -lm -lrt -lpthread
../pidcf77 : ../dcf77/pidcf77.c
$(CC) $(CFLAGS_Piam) -o ../pidcf77 ../dcf77/pidcf77.c $(LDFLAGS_Piam)
CFLAGS_Piopera = -g -O2 -Wno-unused-variable
LDFLAGS_Piopera = -lm
../piopera : ../opera/opera.c
$(CC) $(CFLAGS_Piopera) -o ../piopera ../opera/opera.c $(LDFLAGS_Piopera)
clean:
rm -f ../rpitx ../pissb ../pisstv ../pifsq ../pifm ../piam ../pidcf77 v2rpitx RpiTx.o mailbox.o RpiGpio.o RpiDma.o
install: all
install -m 0755 ../pisstv /usr/bin
install -m 0755 ../pifm /usr/bin
install -m 0755 ../piam /usr/bin
install -m 0755 ../pissb /usr/bin
install -m 0755 ../pifsq /usr/bin
install -m 0755 ../rpitx /usr/bin
install -m 0755 ../pidcf77 /usr/bin
install -m 0755 ../piopera /usr/bin
cp dt-blob.bin /boot/
$(info !!! You should reboot if it is the first installation !!!)

View File

@@ -1,119 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "RpiDma.h"
#include "RpiGpio.h"
static int compareInts(const void* first, const void* second)
{
const int firstInt = *((int*)first);
const int secondInt = *((int*)second);
if (firstInt < secondInt) {
return -1;
}
if (firstInt == secondInt) {
return 0;
}
return 1;
}
char InitDma(void *FunctionTerminate, int* skipSignals)
{
DMA_CHANNEL=4;
char *line = NULL;
size_t size;
FILE * flinux = popen("uname -r", "r");
if (flinux != NULL && getline(&line, &size, flinux) == -1)
{
fprintf(stderr, "Could no get Linux version\n");
}
else
{
if(line[0]=='3')
{
printf("Wheezy\n");
DMA_CHANNEL=DMA_CHANNEL_WHEEZY;
}
if(line[0]=='4')
{
printf("Jessie\n");
DMA_CHANNEL=DMA_CHANNEL_JESSIE;
}
}
pclose(flinux);
//printf("Init DMA\n");
int sentinel[] = {0};
if (skipSignals == NULL) {
skipSignals = sentinel;
}
int sentinelIndex;
for (sentinelIndex = 0; ; ++sentinelIndex) {
if (skipSignals[sentinelIndex] == 0) {
break;
}
}
qsort(skipSignals, sentinelIndex, sizeof(int), compareInts);
// Catch all signals possible - it is vital we kill the DMA engine
// on process exit!
int i;
for (i = 0; i < 64; i++) {
// Some signals are fine, so don't catch them
if (i == *skipSignals) {
++skipSignals;
} else {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = FunctionTerminate;//terminate;
sigaction(i, &sa, NULL);
}
}
//NUM_SAMPLES = NUM_SAMPLES_MAX;
/* Use the mailbox interface to the VC to ask for physical memory */
/*
unlink(MBFILE);
if (mknod(MBFILE, S_IFCHR|0600, makedev(100, 0)) < 0)
{
printf("Failed to create mailbox device\n");
return 0;
}*/
mbox.handle = mbox_open();
if (mbox.handle < 0)
{
printf("Failed to open mailbox\n");
return(0);
}
printf("%d Size NUM PAGES %d PAGE_SIZE %d\n",(sizeof(struct control_data_s)),NUM_PAGES,PAGE_SIZE);
mbox.mem_ref = mem_alloc(mbox.handle, NUM_PAGES* PAGE_SIZE, PAGE_SIZE, mem_flag);
/* TODO: How do we know that succeeded? */
//printf("mem_ref %x\n", mbox.mem_ref);
mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref);
//printf("bus_addr = %x\n", mbox.bus_addr);
mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES* PAGE_SIZE);
//printf("virt_addr %p\n", mbox.virt_addr);
virtbase = (uint8_t *)((uint32_t *)mbox.virt_addr);
//printf("virtbase %p\n", virtbase);
return(1);
}
uint32_t mem_virt_to_phys(volatile void *virt)
{
//MBOX METHOD
uint32_t offset = (uint8_t *)virt - mbox.virt_addr;
return mbox.bus_addr + offset;
}
uint32_t mem_phys_to_virt(volatile uint32_t phys)
{
//MBOX METHOD
uint32_t offset=phys-mbox.bus_addr;
uint32_t result=(uint32_t)((uint8_t *)mbox.virt_addr+offset);
//printf("MemtoVirt:Offset=%lx phys=%lx -> %lx\n",offset,phys,result);
return result;
}

View File

@@ -1,128 +0,0 @@
#ifndef RPI_DMA
#define RPI_DMA
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "mailbox.h"
char InitDma(void *FunctionTerminate, int* skipSignals);
uint32_t mem_virt_to_phys(volatile void *virt);
uint32_t mem_phys_to_virt(volatile uint32_t phys);
#define NBSAMPLES_PWM_FREQ_MAX 500
#define NUM_CB_PWM_FREQUENCY 8
//#define MBFILE DEVICE_FILE_NAME /* From mailbox.h */
#define NUM_SAMPLES_MAX (4000)
#define CBS_SIZE_BY_SAMPLE (3)
#define NUM_CBS_MAIN ((NUM_SAMPLES_MAX * CBS_SIZE_BY_SAMPLE))
#define NUM_CBS (NUM_CBS_MAIN)
#define BCM2708_DMA_SRC_IGNOR (1<<11)
#define BCM2708_DMA_SRC_INC (1<<8)
#define BCM2708_DMA_DST_IGNOR (1<<7)
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
#define BCM2708_DMA_WAIT_RESP (1<<3)
#define BCM2708_DMA_D_DREQ (1<<6)
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
#define BCM2708_DMA_END (1<<1)
#define BCM2708_DMA_RESET (1<<31)
#define BCM2708_DMA_ABORT (1<<30)
#define BCM2708_DMA_INT (1<<2)
#define DMA_CS (0x00/4)
#define DMA_CONBLK_AD (0x04/4)
#define DMA_DEBUG (0x20/4)
#define BUS_TO_PHYS(x) ((x)&~0xC0000000)
#define DMA_CS_RESET (1<<31)
#define DMA_CS_ABORT (1<<30)
#define DMA_CS_DISDEBUG (1<<28)
#define DMA_CS_END (1<<1)
#define DMA_CS_ACTIVE (1<<0)
#define DMA_CS_PRIORITY(x) ((x)&0xf << 16)
#define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20)
#define PAGE_SIZE 4096
#define PAGE_SHIFT 12
#define NUM_PAGES ((sizeof(struct control_data_s) + PAGE_SIZE - 1) >> PAGE_SHIFT)
struct {
int handle; /* From mbox_open() */
unsigned mem_ref; /* From mem_alloc() */
unsigned bus_addr; /* From mem_lock() */
uint8_t *virt_addr; /* From mapmem() */
} mbox;
// The GPU reserves channels 1, 3, 6, and 7 (kernel mask dma.dmachans=0x7f35)
// And, I think sdcard will always get 2 and fbturbo zero
//8 Crash
// 5 seems OK, 14 ALSO
//cat /sys/module/dma/parameters/dmachans
//On Wheezy
//32565: 111111100110101
//On Jessie Pi2:
//3893 : 111100110101
// USE CHANNEL 4 AND 5 which seems to be free
// On Jessie, channel 4 and 5 seems to crash : set to DMA 8 .
#define DMA_CHANNEL_WHEEZY 14
#define DMA_CHANNEL_JESSIE 5
//#define DMA_CHANNEL_PWMFREQUENCY 5
char DMA_CHANNEL;
//#define DMA_CHANNEL 8
#define DMA_CHANNEL_PWMFREQUENCY (DMA_CHANNEL+1)
typedef struct {
uint32_t info, src, dst, length,
stride, next, pad[2];
} dma_cb_t;
typedef struct {
uint8_t *virtaddr;
uint32_t physaddr;
} page_map_t;
page_map_t *page_map;
uint8_t *virtbase;
#define PWM_STEP_MAXI 200
typedef struct {
uint32_t FrequencyTab[PWM_STEP_MAXI];
uint32_t Amplitude1;
uint32_t Amplitude2;
} sample_t;
struct control_data_s {
dma_cb_t cb[NUM_CBS];//+1 ??
sample_t sample[NUM_SAMPLES_MAX];
};
struct control_data_s *ctl;
#endif

View File

@@ -1,97 +0,0 @@
#include "RpiGpio.h"
#include "mailbox.h"
static volatile unsigned int BCM2708_PERI_BASE;
static uint32_t dram_phys_base;
char InitGpio()
{
int rev, mem, maker, overVolted ;
//printf("*********** Init GPIO *************\n");
RASPBERRY_PI_INFO_T info;
if (getRaspberryPiInformation(&info) > 0)
{
if(info.peripheralBase==RPI_BROADCOM_2835_PERIPHERAL_BASE)
{
BCM2708_PERI_BASE = info.peripheralBase ;
dram_phys_base = 0x40000000;
mem_flag = MEM_FLAG_L1_NONALLOCATING|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x0c;
}
if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE))
{
BCM2708_PERI_BASE = info.peripheralBase ;
dram_phys_base = 0xc0000000;
mem_flag = MEM_FLAG_L1_NONALLOCATING/*MEM_FLAG_DIRECT*/|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x04;
}
}
DisplayInfo();
dma_reg = map_peripheral(DMA_BASE, DMA_LEN);
pwm_reg = map_peripheral(PWM_BASE, PWM_LEN);
clk_reg = map_peripheral(CLK_BASE, CLK_LEN);
pcm_reg = map_peripheral(PCM_BASE, PCM_LEN);
gpio_reg = map_peripheral(GPIO_BASE, GPIO_LEN);
pad_gpios_reg = map_peripheral(PADS_GPIO, PADS_GPIO_LEN);
return 1;
}
void * map_peripheral(uint32_t base, uint32_t len)
{
void * vaddr;
vaddr=mapmem(base,len);
//printf("Vaddr =%lx \n",vaddr);
return vaddr;
}
int gpioSetMode(unsigned gpio, unsigned mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpio_reg[reg] = (gpio_reg[reg] & ~(7<<shift)) | (mode<<shift);
return 0;
}
void DisplayInfo()
{
if (getRaspberryPiInformation(&info) > 0)
{
printf("memory: %s\n", raspberryPiMemoryToString(info.memory));
printf("processor: %s\n",
raspberryPiProcessorToString(info.processor));
printf("i2cDevice: %s\n",
raspberryPiI2CDeviceToString(info.i2cDevice));
printf("model: %s\n",
raspberryPiModelToString(info.model));
printf("manufacturer: %s\n",
raspberryPiManufacturerToString(info.manufacturer));
printf("pcb revision: %d\n", info.pcbRevision);
printf("warranty void: %s\n", (info.warrantyBit) ? "yes" : "no");
printf("revision: %04x\n", info.revisionNumber);
printf("peripheral base: 0x%x\n", info.peripheralBase);
}
}

View File

@@ -1,110 +0,0 @@
#ifndef RPI_GPIO
#define RPI_GPIO
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <ctype.h>
#include "raspberry_pi_revision.h"
char InitGpio(void);
void DisplayInfo();
int model;
uint32_t mem_flag;
volatile uint32_t *pwm_reg;
volatile uint32_t *clk_reg;
volatile uint32_t *dma_reg;
volatile uint32_t *gpio_reg;
volatile uint32_t *pcm_reg;
volatile uint32_t *pad_gpios_reg;
void * map_peripheral(uint32_t base, uint32_t len);
int gpioSetMode(unsigned gpio, unsigned mode);
RASPBERRY_PI_INFO_T info;
#define DMA_BASE (BCM2708_PERI_BASE + 0x00007000 )
#define DMA_LEN 0xF00
#define PWM_BASE (BCM2708_PERI_BASE + 0x0020C000)
#define PWM_LEN 0x28
#define CLK_BASE (BCM2708_PERI_BASE + 0x00101000)
#define CLK_LEN 0xA8
#define GPIO_BASE (BCM2708_PERI_BASE + 0x00200000)
#define GPIO_LEN 0xB4
#define PCM_BASE (BCM2708_PERI_BASE + 0x00203000)
#define PCM_LEN 0x24
#define PADS_GPIO (BCM2708_PERI_BASE + 0x00100000)
#define PADS_GPIO_LEN (0x40/4)
#define PADS_GPIO_0 (0x2C/4)
#define PADS_GPIO_1 (0x30/4)
#define PADS_GPIO_2 (0x34/4)
#define PWM_CTL (0x00/4)
#define PWM_DMAC (0x08/4)
#define PWM_RNG1 (0x10/4)
#define PWM_RNG2 (0x20/4)
#define PWM_FIFO (0x18/4)
#define PWMCLK_CNTL 40
#define PWMCLK_DIV 41
#define GPCLK_CNTL (0x70/4)
#define GPCLK_DIV (0x74/4)
#define PWMCTL_MSEN2 (1<<15)
#define PWMCTL_USEF2 (1<<13)
#define PWMCTL_RPTL2 (1<<10)
#define PWMCTL_MODE2 (1<<9)
#define PWMCTL_PWEN2 (1<<8)
#define PWMCTL_MSEN1 (1<<7)
#define PWMCTL_CLRF (1<<6)
#define PWMCTL_USEF1 (1<<5)
#define PWMCTL_POLA1 (1<<4)
#define PWMCTL_RPTL1 (1<<2)
#define PWMCTL_MODE1 (1<<1)
#define PWMCTL_PWEN1 (1<<0)
#define PWMDMAC_ENAB (1<<31)
#define PWMDMAC_THRSHLD ((15<<8)|(15<<0))
#define PCM_CS_A (0x00/4)
#define PCM_FIFO_A (0x04/4)
#define PCM_MODE_A (0x08/4)
#define PCM_RXC_A (0x0c/4)
#define PCM_TXC_A (0x10/4)
#define PCM_DREQ_A (0x14/4)
#define PCM_INTEN_A (0x18/4)
#define PCM_INT_STC_A (0x1c/4)
#define PCM_GRAY (0x20/4)
#define PCMCLK_CNTL 38
#define PCMCLK_DIV 39
#define GPFSEL0 (0x00/4)
#define GPFSEL1 (0x04/4)
#define GPFSEL2 (0x08/4)
#define GPPUD (0x94/4)
#define GPPUDCLK0 (0x9C/4)
// ---- Memory allocating defines
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
#define MEM_FLAG_DISCARDABLE (1 << 0) /* can be resized to 0 at any time. Use for cached data */
#define MEM_FLAG_NORMAL (0 << 2) /* normal allocating alias. Don't use from ARM */
#define MEM_FLAG_DIRECT (1 << 2) /* 0xC alias uncached */
#define MEM_FLAG_COHERENT (2 << 2) /* 0x8 alias. Non-allocating in L2 but coherent */
#define MEM_FLAG_L1_NONALLOCATING (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT) /* Allocating in L2 */
#define MEM_FLAG_ZERO ( 1 << 4) /* initialise buffer to all zeros */
#define MEM_FLAG_NO_INIT ( 1 << 5) /* don't initialise (default is initialise to all ones */
#define MEM_FLAG_HINT_PERMALOCK (1 << 6) /* Likely to be locked for long periods of time. */
#endif

View File

@@ -1,123 +0,0 @@
#include "stdio.h"
#include "amdmasync.h"
#include <math.h>
amdmasync::amdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,3,2)
{
tunefreq=TuneFrequency;
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate);
clkgpio::SetFrequency(0);
clkgpio::enableclk(4); // GPIO 4 CLK by default
syncwithpwm=false;
if(syncwithpwm)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SampleRate);
}
else
{
pcmgpio::SetPllNumber(clk_plld,1);
pcmgpio::SetFrequency(SampleRate);
}
padgpio pad;
Originfsel=pad.gpioreg[PADS_GPIO_0];
SetDmaAlgo();
}
amdmasync::~amdmasync()
{
clkgpio::disableclk(4);
padgpio pad;
pad.gpioreg[PADS_GPIO_0]=Originfsel;
}
void amdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
//@0
//Set Amplitude by writing to PADS
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
cbp++;
//@1
//Set Amplitude to FSEL for amplitude=0
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]);
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
cbp++;
// Delay
if(syncwithpwm)
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
else
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
if(syncwithpwm)
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
else
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void amdmasync::SetAmSample(uint32_t Index,float Amplitude) //-1;1
{
Index=Index%buffersize;
int IntAmplitude=round(abs(Amplitude)*8.0)-1;
int IntAmplitudePAD=IntAmplitude;
if(IntAmplitudePAD>7) IntAmplitudePAD=7;
if(IntAmplitudePAD<0) IntAmplitudePAD=0;
//fprintf(stderr,"Amplitude=%f PAD %d\n",Amplitude,IntAmplitudePAD);
sampletab[Index*registerbysample]=(0x5A<<24) + (IntAmplitudePAD&0x7) + (1<<4) + (0<<3); // Amplitude PAD
//sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
if(IntAmplitude==-1)
{
sampletab[Index*registerbysample+1]=(Originfsel & ~(7 << 12)) | (0 << 12); //Pin is in -> Amplitude 0
}
else
{
sampletab[Index*registerbysample+1]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
}
PushSample(Index);
}

View File

@@ -1,22 +0,0 @@
#ifndef DEF_AMDMASYNC
#define DEF_AMDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class amdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
{
protected:
uint64_t tunefreq;
bool syncwithpwm;
uint32_t Originfsel;
public:
amdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
~amdmasync();
void SetDmaAlgo();
void SetAmSample(uint32_t Index,float Amplitude);
};
#endif

Binary file not shown.

View File

@@ -1,203 +0,0 @@
void InitCalibrationTabPi2(void)
{
CalibrationTab[1]=1504;
CalibrationTab[2]=1777;
CalibrationTab[3]=2048;
CalibrationTab[4]=2361;
CalibrationTab[5]=2617;
CalibrationTab[6]=2865;
CalibrationTab[7]=3082;
CalibrationTab[8]=3315;
CalibrationTab[9]=3538;
CalibrationTab[10]=3774;
CalibrationTab[11]=3968;
CalibrationTab[12]=4219;
CalibrationTab[13]=4452;
CalibrationTab[14]=4689;
CalibrationTab[15]=4900;
CalibrationTab[16]=5127;
CalibrationTab[17]=5315;
CalibrationTab[18]=5507;
CalibrationTab[19]=5660;
CalibrationTab[20]=5830;
CalibrationTab[21]=5975;
CalibrationTab[22]=6129;
CalibrationTab[23]=6286;
CalibrationTab[24]=6444;
CalibrationTab[25]=6603;
CalibrationTab[26]=6756;
CalibrationTab[27]=6915;
CalibrationTab[28]=7072;
CalibrationTab[29]=7231;
CalibrationTab[30]=7389;
CalibrationTab[31]=7539;
CalibrationTab[32]=7707;
CalibrationTab[33]=7838;
CalibrationTab[34]=8002;
CalibrationTab[35]=8158;
CalibrationTab[36]=8315;
CalibrationTab[37]=8474;
CalibrationTab[38]=8634;
CalibrationTab[39]=8790;
CalibrationTab[40]=8943;
CalibrationTab[41]=9105;
CalibrationTab[42]=9260;
CalibrationTab[43]=9415;
CalibrationTab[44]=9569;
CalibrationTab[45]=9745;
CalibrationTab[46]=9883;
CalibrationTab[47]=10032;
CalibrationTab[48]=10197;
CalibrationTab[49]=10351;
CalibrationTab[50]=10509;
CalibrationTab[51]=10663;
CalibrationTab[52]=10823;
CalibrationTab[53]=10981;
CalibrationTab[54]=11138;
CalibrationTab[55]=11295;
CalibrationTab[56]=11450;
CalibrationTab[57]=11616;
CalibrationTab[58]=11745;
CalibrationTab[59]=11910;
CalibrationTab[60]=12067;
CalibrationTab[61]=12216;
CalibrationTab[62]=12380;
CalibrationTab[63]=12534;
CalibrationTab[64]=12697;
CalibrationTab[65]=12850;
CalibrationTab[66]=13012;
CalibrationTab[67]=13164;
CalibrationTab[68]=13319;
CalibrationTab[69]=13477;
CalibrationTab[70]=13653;
CalibrationTab[71]=13786;
CalibrationTab[72]=13944;
CalibrationTab[73]=14103;
CalibrationTab[74]=14259;
CalibrationTab[75]=14411;
CalibrationTab[76]=14569;
CalibrationTab[77]=14730;
CalibrationTab[78]=14887;
CalibrationTab[79]=15036;
CalibrationTab[80]=15202;
CalibrationTab[81]=15356;
CalibrationTab[82]=15519;
CalibrationTab[83]=15648;
CalibrationTab[84]=15816;
CalibrationTab[85]=15973;
CalibrationTab[86]=16119;
CalibrationTab[87]=16284;
CalibrationTab[88]=16445;
CalibrationTab[89]=16602;
CalibrationTab[90]=16758;
CalibrationTab[91]=16920;
CalibrationTab[92]=17072;
CalibrationTab[93]=17228;
CalibrationTab[94]=17381;
CalibrationTab[95]=17556;
CalibrationTab[96]=17694;
CalibrationTab[97]=17850;
CalibrationTab[98]=18012;
CalibrationTab[99]=18164;
CalibrationTab[100]=18317;
CalibrationTab[101]=18474;
CalibrationTab[102]=18637;
CalibrationTab[103]=18790;
CalibrationTab[104]=18949;
CalibrationTab[105]=19107;
CalibrationTab[106]=19262;
CalibrationTab[107]=19423;
CalibrationTab[108]=19550;
CalibrationTab[109]=19722;
CalibrationTab[110]=19881;
CalibrationTab[111]=20028;
CalibrationTab[112]=20192;
CalibrationTab[113]=20354;
CalibrationTab[114]=20505;
CalibrationTab[115]=20664;
CalibrationTab[116]=20823;
CalibrationTab[117]=20978;
CalibrationTab[118]=21135;
CalibrationTab[119]=21288;
CalibrationTab[120]=21462;
CalibrationTab[121]=21604;
CalibrationTab[122]=21759;
CalibrationTab[123]=21917;
CalibrationTab[124]=22071;
CalibrationTab[125]=22222;
CalibrationTab[126]=22384;
CalibrationTab[127]=22534;
CalibrationTab[128]=22699;
CalibrationTab[129]=22855;
CalibrationTab[130]=23014;
CalibrationTab[131]=23168;
CalibrationTab[132]=23326;
CalibrationTab[133]=23450;
CalibrationTab[134]=23626;
CalibrationTab[135]=23785;
CalibrationTab[136]=23934;
CalibrationTab[137]=24099;
CalibrationTab[138]=24264;
CalibrationTab[139]=24407;
CalibrationTab[140]=24571;
CalibrationTab[141]=24725;
CalibrationTab[142]=24887;
CalibrationTab[143]=25033;
CalibrationTab[144]=25193;
CalibrationTab[145]=25370;
CalibrationTab[146]=25511;
CalibrationTab[147]=25664;
CalibrationTab[148]=25825;
CalibrationTab[149]=25978;
CalibrationTab[150]=26129;
CalibrationTab[151]=26285;
CalibrationTab[152]=26448;
CalibrationTab[153]=26604;
CalibrationTab[154]=26764;
CalibrationTab[155]=26918;
CalibrationTab[156]=27081;
CalibrationTab[157]=27238;
CalibrationTab[158]=27352;
CalibrationTab[159]=27531;
CalibrationTab[160]=27692;
CalibrationTab[161]=27845;
CalibrationTab[162]=28005;
CalibrationTab[163]=28164;
CalibrationTab[164]=28313;
CalibrationTab[165]=28478;
CalibrationTab[166]=28633;
CalibrationTab[167]=28791;
CalibrationTab[168]=28948;
CalibrationTab[169]=29099;
CalibrationTab[170]=29271;
CalibrationTab[171]=29415;
CalibrationTab[172]=29569;
CalibrationTab[173]=29729;
CalibrationTab[174]=29885;
CalibrationTab[175]=30031;
CalibrationTab[176]=30196;
CalibrationTab[177]=30352;
CalibrationTab[178]=30508;
CalibrationTab[179]=30670;
CalibrationTab[180]=30827;
CalibrationTab[181]=30986;
CalibrationTab[182]=31146;
CalibrationTab[183]=31254;
CalibrationTab[184]=31441;
CalibrationTab[185]=31597;
CalibrationTab[186]=31751;
CalibrationTab[187]=31911;
CalibrationTab[188]=32070;
CalibrationTab[189]=32219;
CalibrationTab[190]=32386;
CalibrationTab[191]=32535;
CalibrationTab[192]=32699;
CalibrationTab[193]=32854;
CalibrationTab[194]=33007;
CalibrationTab[195]=33176;
CalibrationTab[196]=33323;
CalibrationTab[197]=33475;
CalibrationTab[198]=33636;
CalibrationTab[199]=33790;
}

View File

@@ -1,202 +0,0 @@
void InitCalibrationTabPi3(void)
{
CalibrationTab[1]=1260;
CalibrationTab[2]=1509;
CalibrationTab[3]=1761;
CalibrationTab[4]=1998;
CalibrationTab[5]=2255;
CalibrationTab[6]=2490;
CalibrationTab[7]=2702;
CalibrationTab[8]=2919;
CalibrationTab[9]=3111;
CalibrationTab[10]=3319;
CalibrationTab[11]=3515;
CalibrationTab[12]=3732;
CalibrationTab[13]=3900;
CalibrationTab[14]=4100;
CalibrationTab[15]=4295;
CalibrationTab[16]=4510;
CalibrationTab[17]=4699;
CalibrationTab[18]=4881;
CalibrationTab[19]=5033;
CalibrationTab[20]=5191;
CalibrationTab[21]=5344;
CalibrationTab[22]=5501;
CalibrationTab[23]=5658;
CalibrationTab[24]=5849;
CalibrationTab[25]=5974;
CalibrationTab[26]=6121;
CalibrationTab[27]=6288;
CalibrationTab[28]=6443;
CalibrationTab[29]=6599;
CalibrationTab[30]=6757;
CalibrationTab[31]=6911;
CalibrationTab[32]=7072;
CalibrationTab[33]=7231;
CalibrationTab[34]=7386;
CalibrationTab[35]=7547;
CalibrationTab[36]=7715;
CalibrationTab[37]=7811;
CalibrationTab[38]=7989;
CalibrationTab[39]=8149;
CalibrationTab[40]=8311;
CalibrationTab[41]=8470;
CalibrationTab[42]=8630;
CalibrationTab[43]=8785;
CalibrationTab[44]=8940;
CalibrationTab[45]=9100;
CalibrationTab[46]=9254;
CalibrationTab[47]=9407;
CalibrationTab[48]=9566;
CalibrationTab[49]=9751;
CalibrationTab[50]=9881;
CalibrationTab[51]=10029;
CalibrationTab[52]=10192;
CalibrationTab[53]=10350;
CalibrationTab[54]=10504;
CalibrationTab[55]=10661;
CalibrationTab[56]=10816;
CalibrationTab[57]=10977;
CalibrationTab[58]=11136;
CalibrationTab[59]=11293;
CalibrationTab[60]=11448;
CalibrationTab[61]=11617;
CalibrationTab[62]=11716;
CalibrationTab[63]=11895;
CalibrationTab[64]=12056;
CalibrationTab[65]=12214;
CalibrationTab[66]=12374;
CalibrationTab[67]=12534;
CalibrationTab[68]=12691;
CalibrationTab[69]=12848;
CalibrationTab[70]=13007;
CalibrationTab[71]=13162;
CalibrationTab[72]=13314;
CalibrationTab[73]=13473;
CalibrationTab[74]=13651;
CalibrationTab[75]=13788;
CalibrationTab[76]=13936;
CalibrationTab[77]=14099;
CalibrationTab[78]=14257;
CalibrationTab[79]=14409;
CalibrationTab[80]=14568;
CalibrationTab[81]=14724;
CalibrationTab[82]=14885;
CalibrationTab[83]=15041;
CalibrationTab[84]=15200;
CalibrationTab[85]=15357;
CalibrationTab[86]=15522;
CalibrationTab[87]=15624;
CalibrationTab[88]=15803;
CalibrationTab[89]=15962;
CalibrationTab[90]=16117;
CalibrationTab[91]=16276;
CalibrationTab[92]=16438;
CalibrationTab[93]=16596;
CalibrationTab[94]=16755;
CalibrationTab[95]=16918;
CalibrationTab[96]=17070;
CalibrationTab[97]=17220;
CalibrationTab[98]=17378;
CalibrationTab[99]=17553;
CalibrationTab[100]=17695;
CalibrationTab[101]=17843;
CalibrationTab[102]=18005;
CalibrationTab[103]=18161;
CalibrationTab[104]=18313;
CalibrationTab[105]=18478;
CalibrationTab[106]=18630;
CalibrationTab[107]=18792;
CalibrationTab[108]=18945;
CalibrationTab[109]=19104;
CalibrationTab[110]=19266;
CalibrationTab[111]=19436;
CalibrationTab[112]=19534;
CalibrationTab[113]=19711;
CalibrationTab[114]=19870;
CalibrationTab[115]=20024;
CalibrationTab[116]=20183;
CalibrationTab[117]=20342;
CalibrationTab[118]=20501;
CalibrationTab[119]=20661;
CalibrationTab[120]=20819;
CalibrationTab[121]=20977;
CalibrationTab[122]=21131;
CalibrationTab[123]=21282;
CalibrationTab[124]=21454;
CalibrationTab[125]=21599;
CalibrationTab[126]=21751;
CalibrationTab[127]=21912;
CalibrationTab[128]=22068;
CalibrationTab[129]=22220;
CalibrationTab[130]=22380;
CalibrationTab[131]=22540;
CalibrationTab[132]=22695;
CalibrationTab[133]=22854;
CalibrationTab[134]=23008;
CalibrationTab[135]=23174;
CalibrationTab[136]=23347;
CalibrationTab[137]=23440;
CalibrationTab[138]=23618;
CalibrationTab[139]=23776;
CalibrationTab[140]=23932;
CalibrationTab[141]=24091;
CalibrationTab[142]=24251;
CalibrationTab[143]=24403;
CalibrationTab[144]=24563;
CalibrationTab[145]=24722;
CalibrationTab[146]=24883;
CalibrationTab[147]=25035;
CalibrationTab[148]=25188;
CalibrationTab[149]=25361;
CalibrationTab[150]=25506;
CalibrationTab[151]=25656;
CalibrationTab[152]=25818;
CalibrationTab[153]=25977;
CalibrationTab[154]=26130;
CalibrationTab[155]=26287;
CalibrationTab[156]=26447;
CalibrationTab[157]=26597;
CalibrationTab[158]=26764;
CalibrationTab[159]=26915;
CalibrationTab[160]=27082;
CalibrationTab[161]=27262;
CalibrationTab[162]=27343;
CalibrationTab[163]=27520;
CalibrationTab[164]=27683;
CalibrationTab[165]=27839;
CalibrationTab[166]=28000;
CalibrationTab[167]=28158;
CalibrationTab[168]=28308;
CalibrationTab[169]=28469;
CalibrationTab[170]=28629;
CalibrationTab[171]=28786;
CalibrationTab[172]=28945;
CalibrationTab[173]=29095;
CalibrationTab[174]=29261;
CalibrationTab[175]=29413;
CalibrationTab[176]=29563;
CalibrationTab[177]=29726;
CalibrationTab[178]=29883;
CalibrationTab[179]=30037;
CalibrationTab[180]=30196;
CalibrationTab[181]=30353;
CalibrationTab[182]=30499;
CalibrationTab[183]=30668;
CalibrationTab[184]=30822;
CalibrationTab[185]=30987;
CalibrationTab[186]=31164;
CalibrationTab[187]=31247;
CalibrationTab[188]=31427;
CalibrationTab[189]=31589;
CalibrationTab[190]=31750;
CalibrationTab[191]=31906;
CalibrationTab[192]=32063;
CalibrationTab[193]=32215;
CalibrationTab[194]=32378;
CalibrationTab[195]=32533;
CalibrationTab[196]=32690;
CalibrationTab[197]=32848;
CalibrationTab[198]=33004;
CalibrationTab[199]=33164;}

View File

@@ -1,203 +0,0 @@
void InitCalibrationTabPiZero(void)
{
CalibrationTab[1]=1135;
CalibrationTab[2]=1317;
CalibrationTab[3]=1521;
CalibrationTab[4]=1712;
CalibrationTab[5]=1891;
CalibrationTab[6]=2064;
CalibrationTab[7]=2239;
CalibrationTab[8]=2414;
CalibrationTab[9]=2578;
CalibrationTab[10]=2752;
CalibrationTab[11]=2894;
CalibrationTab[12]=3057;
CalibrationTab[13]=3212;
CalibrationTab[14]=3363;
CalibrationTab[15]=3527;
CalibrationTab[16]=3714;
CalibrationTab[17]=3866;
CalibrationTab[18]=3979;
CalibrationTab[19]=4175;
CalibrationTab[20]=4316;
CalibrationTab[21]=4512;
CalibrationTab[22]=4627;
CalibrationTab[23]=4805;
CalibrationTab[24]=4930;
CalibrationTab[25]=5104;
CalibrationTab[26]=5281;
CalibrationTab[27]=5408;
CalibrationTab[28]=5578;
CalibrationTab[29]=5759;
CalibrationTab[30]=5882;
CalibrationTab[31]=6044;
CalibrationTab[32]=6208;
CalibrationTab[33]=6349;
CalibrationTab[34]=6507;
CalibrationTab[35]=6678;
CalibrationTab[36]=6831;
CalibrationTab[37]=7036;
CalibrationTab[38]=7121;
CalibrationTab[39]=7292;
CalibrationTab[40]=7464;
CalibrationTab[41]=7620;
CalibrationTab[42]=7796;
CalibrationTab[43]=7929;
CalibrationTab[44]=8254;
CalibrationTab[45]=8232;
CalibrationTab[46]=8398;
CalibrationTab[47]=8533;
CalibrationTab[48]=8701;
CalibrationTab[49]=8881;
CalibrationTab[50]=9055;
CalibrationTab[51]=9149;
CalibrationTab[52]=9320;
CalibrationTab[53]=9489;
CalibrationTab[54]=9647;
CalibrationTab[55]=9774;
CalibrationTab[56]=9952;
CalibrationTab[57]=10105;
CalibrationTab[58]=10277;
CalibrationTab[59]=10544;
CalibrationTab[60]=10579;
CalibrationTab[61]=10722;
CalibrationTab[62]=10887;
CalibrationTab[63]=11046;
CalibrationTab[64]=11207;
CalibrationTab[65]=11364;
CalibrationTab[66]=11690;
CalibrationTab[67]=11697;
CalibrationTab[68]=11826;
CalibrationTab[69]=11973;
CalibrationTab[70]=12141;
CalibrationTab[71]=12311;
CalibrationTab[72]=12513;
CalibrationTab[73]=12679;
CalibrationTab[74]=12736;
CalibrationTab[75]=12911;
CalibrationTab[76]=13071;
CalibrationTab[77]=13234;
CalibrationTab[78]=13381;
CalibrationTab[79]=13579;
CalibrationTab[80]=13688;
CalibrationTab[81]=13861;
CalibrationTab[82]=14182;
CalibrationTab[83]=14209;
CalibrationTab[84]=14328;
CalibrationTab[85]=14485;
CalibrationTab[86]=14653;
CalibrationTab[87]=14799;
CalibrationTab[88]=14948;
CalibrationTab[89]=15119;
CalibrationTab[90]=15275;
CalibrationTab[91]=15453;
CalibrationTab[92]=15741;
CalibrationTab[93]=15841;
CalibrationTab[94]=15875;
CalibrationTab[95]=16029;
CalibrationTab[96]=16294;
CalibrationTab[97]=16368;
CalibrationTab[98]=16516;
CalibrationTab[99]=16682;
CalibrationTab[100]=16834;
CalibrationTab[101]=16961;
CalibrationTab[102]=17148;
CalibrationTab[103]=17315;
CalibrationTab[104]=17453;
CalibrationTab[105]=17621;
CalibrationTab[106]=17772;
CalibrationTab[107]=17944;
CalibrationTab[108]=18129;
CalibrationTab[109]=18319;
CalibrationTab[110]=18387;
CalibrationTab[111]=18548;
CalibrationTab[112]=18690;
CalibrationTab[113]=18872;
CalibrationTab[114]=19046;
CalibrationTab[115]=19166;
CalibrationTab[116]=19338;
CalibrationTab[117]=19531;
CalibrationTab[118]=19627;
CalibrationTab[119]=19813;
CalibrationTab[120]=20050;
CalibrationTab[121]=20106;
CalibrationTab[122]=20273;
CalibrationTab[123]=20434;
CalibrationTab[124]=20613;
CalibrationTab[125]=20853;
CalibrationTab[126]=21102;
CalibrationTab[127]=21134;
CalibrationTab[128]=21185;
CalibrationTab[129]=21347;
CalibrationTab[130]=21592;
CalibrationTab[131]=21666;
CalibrationTab[132]=21834;
CalibrationTab[133]=21991;
CalibrationTab[134]=22143;
CalibrationTab[135]=22304;
CalibrationTab[136]=22437;
CalibrationTab[137]=22638;
CalibrationTab[138]=22767;
CalibrationTab[139]=22929;
CalibrationTab[140]=23178;
CalibrationTab[141]=23241;
CalibrationTab[142]=23413;
CalibrationTab[143]=23551;
CalibrationTab[144]=23784;
CalibrationTab[145]=23835;
CalibrationTab[146]=24010;
CalibrationTab[147]=24187;
CalibrationTab[148]=24345;
CalibrationTab[149]=24573;
CalibrationTab[150]=24658;
CalibrationTab[151]=24802;
CalibrationTab[152]=24963;
CalibrationTab[153]=25151;
CalibrationTab[154]=25370;
CalibrationTab[155]=25401;
CalibrationTab[156]=25567;
CalibrationTab[157]=25813;
CalibrationTab[158]=25890;
CalibrationTab[159]=26055;
CalibrationTab[160]=26182;
CalibrationTab[161]=26387;
CalibrationTab[162]=26504;
CalibrationTab[163]=26684;
CalibrationTab[164]=26833;
CalibrationTab[165]=27080;
CalibrationTab[166]=27207;
CalibrationTab[167]=27308;
CalibrationTab[168]=27444;
CalibrationTab[169]=27617;
CalibrationTab[170]=27790;
CalibrationTab[171]=27933;
CalibrationTab[172]=28097;
CalibrationTab[173]=28320;
CalibrationTab[174]=28390;
CalibrationTab[175]=28559;
CalibrationTab[176]=28707;
CalibrationTab[177]=28873;
CalibrationTab[178]=29016;
CalibrationTab[179]=29191;
CalibrationTab[180]=29407;
CalibrationTab[181]=29494;
CalibrationTab[182]=29644;
CalibrationTab[183]=29812;
CalibrationTab[184]=29936;
CalibrationTab[185]=30110;
CalibrationTab[186]=30274;
CalibrationTab[187]=30496;
CalibrationTab[188]=30613;
CalibrationTab[189]=30762;
CalibrationTab[190]=30932;
CalibrationTab[191]=31146;
CalibrationTab[192]=31604;
CalibrationTab[193]=31659;
CalibrationTab[194]=31714;
CalibrationTab[195]=31716;
CalibrationTab[196]=31796;
CalibrationTab[197]=31973;
CalibrationTab[198]=32129;
CalibrationTab[199]=32299;
}

View File

@@ -1,253 +0,0 @@
#include "dma.h"
#include "stdio.h"
extern "C"
{
#include "mailbox.h"
#include "raspberry_pi_revision.h"
}
#include <unistd.h>
#define BUS_TO_PHYS(x) ((x)&~0xC0000000)
dma::dma(int Channel,uint32_t CBSize,uint32_t UserMemSize) // Fixme! Need to check to be 256 Aligned for UserMem
{
fprintf(stderr,"Channel %d CBSize %d UsermemSize %d\n",Channel,CBSize,UserMemSize);
channel=Channel;
mbox.handle = mbox_open();
if (mbox.handle < 0)
{
fprintf(stderr,"Failed to open mailbox\n");
}
cbsize=CBSize;
usermemsize=UserMemSize;
GetRpiInfo(); // Fill mem_flag and dram_phys_base
uint32_t MemoryRequired=CBSize*sizeof(dma_cb_t)+UserMemSize*sizeof(uint32_t);
int NumPages=(MemoryRequired/PAGE_SIZE)+1;
fprintf(stderr,"%d Size NUM PAGES %d PAGE_SIZE %d\n",MemoryRequired,NumPages,PAGE_SIZE);
mbox.mem_ref = mem_alloc(mbox.handle, NumPages* PAGE_SIZE, PAGE_SIZE, mem_flag);
/* TODO: How do we know that succeeded? */
//fprintf(stderr,"mem_ref %x\n", mbox.mem_ref);
mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref);
//fprintf(stderr,"bus_addr = %x\n", mbox.bus_addr);
mbox.virt_addr = (uint8_t *)mapmem(BUS_TO_PHYS(mbox.bus_addr), NumPages* PAGE_SIZE);
//fprintf(stderr,"virt_addr %p\n", mbox.virt_addr);
virtbase = (uint8_t *)((uint32_t *)mbox.virt_addr);
//fprintf(stderr,"virtbase %p\n", virtbase);
cbarray = (dma_cb_t *)virtbase; // We place DMA Control Blocks (CB) at beginning of virtual memory
//fprintf(stderr,"cbarray %p\n", cbarray);
usermem= (unsigned int *)(virtbase+CBSize*sizeof(dma_cb_t)); // user memory is placed after
//fprintf(stderr,"usermem %p\n", usermem);
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET|DMA_CS_INT; // Remove int flag
usleep(100);
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void*)cbarray ); // reset to beginning
}
void dma::GetRpiInfo()
{
RASPBERRY_PI_INFO_T info;
if (getRaspberryPiInformation(&info) > 0)
{
if(info.peripheralBase==RPI_BROADCOM_2835_PERIPHERAL_BASE)
{
dram_phys_base = 0x40000000;
mem_flag = MEM_FLAG_L1_NONALLOCATING|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x0c;
}
if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE))
{
dram_phys_base = 0xc0000000;
mem_flag = MEM_FLAG_L1_NONALLOCATING/*MEM_FLAG_DIRECT*/|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x04;
}
}
else
{
fprintf(stderr,"Unknown Raspberry architecture\n");
}
}
dma::~dma()
{
/*
unmapmem(mbox.virt_addr, NumPages * PAGE_SIZE);
*/
mem_unlock(mbox.handle, mbox.mem_ref);
mem_free(mbox.handle, mbox.mem_ref);
}
uint32_t dma::mem_virt_to_phys(volatile void *virt)
{
//MBOX METHOD
uint32_t offset = (uint8_t *)virt - mbox.virt_addr;
return mbox.bus_addr + offset;
}
uint32_t dma::mem_phys_to_virt(volatile uint32_t phys)
{
//MBOX METHOD
uint32_t offset=phys-mbox.bus_addr;
uint32_t result=(uint32_t)((uint8_t *)mbox.virt_addr+offset);
//printf("MemtoVirt:Offset=%lx phys=%lx -> %lx\n",offset,phys,result);
return result;
}
int dma::start()
{
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET;
usleep(100);
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void*)cbarray ); // reset to beginning
dma_reg.gpioreg[DMA_DEBUG+channel*0x40] = 7; // clear debug error flags
usleep(100);
dma_reg.gpioreg[DMA_CS+channel*0x40] = DMA_CS_PRIORITY(15) | DMA_CS_PANIC_PRIORITY(15) | DMA_CS_DISDEBUG |DMA_CS_ACTIVE;
return 0;
}
int dma::stop()
{
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET;
usleep(1000);
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_INT | BCM2708_DMA_END;
usleep(100);
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void *)cbarray );
usleep(100);
dma_reg.gpioreg[DMA_DEBUG+channel*0x40] = 7; // clear debug error flags
usleep(100);
return 0;
}
int dma::getcbposition()
{
volatile uint32_t dmacb=(uint32_t)(dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]);
//fprintf(stderr,"cb=%x\n",dmacb);
if(dmacb>0)
return mem_phys_to_virt(dmacb)-(uint32_t)virtbase;
else
return -1;
// dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]-mem_virt_to_phys((void *)cbarray );
}
bool dma::isrunning()
{
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_ACTIVE)>0);
}
bool dma::isunderflow()
{
//if((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0) fprintf(stderr,"Status:%x\n",dma_reg.gpioreg[DMA_CS+channel*0x40]);
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0);
}
//**************************************** BUFFER DMA ********************************************************
bufferdma::bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample):dma(Channel,tbuffersize*tcbbysample,tbuffersize*tregisterbysample)
{
buffersize=tbuffersize;
cbbysample=tcbbysample;
registerbysample=tregisterbysample;
fprintf(stderr,"BufferSize %d , cb %d user %d\n",buffersize,buffersize*cbbysample,buffersize*registerbysample);
current_sample=0;
last_sample=0;
sample_available=buffersize;
sampletab=usermem;
}
void bufferdma::SetDmaAlgo()
{
}
int bufferdma::GetBufferAvailable()
{
int diffsample=0;
if(Started)
{
int CurrenCbPos=getcbposition();
if(CurrenCbPos!=-1)
{
current_sample=CurrenCbPos/(sizeof(dma_cb_t)*cbbysample);
}
else
{
fprintf(stderr,"DMA WEIRD STATE\n");
current_sample=0;
}
//fprintf(stderr,"CurrentCB=%d\n",current_sample);
diffsample=current_sample-last_sample;
if(diffsample<0) diffsample+=buffersize;
//fprintf(stderr,"cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
}
else
{
//last_sample=buffersize-1;
diffsample=buffersize;
current_sample=0;
//fprintf(stderr,"Warning DMA stopped \n");
//fprintf(stderr,"S:cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
}
/*
if(isunderflow())
{
fprintf(stderr,"cur %d last %d \n",current_sample,last_sample);
fprintf(stderr,"Underflow\n");
}*/
return diffsample;
}
int bufferdma::GetUserMemIndex()
{
int IndexAvailable=-1;
//fprintf(stderr,"Avail=%d\n",GetBufferAvailable());
if(GetBufferAvailable())
{
IndexAvailable=last_sample+1;
if(IndexAvailable>=(int)buffersize) IndexAvailable=0;
}
return IndexAvailable;
}
int bufferdma::PushSample(int Index)
{
if(Index<0) return -1; // No buffer available
/*
dma_cb_t *cbp;
cbp=&cbarray[last_sample*cbbysample+cbbysample-1];
cbp->info=cbp->info&(~BCM2708_DMA_SET_INT);
*/
last_sample=Index;
/*
cbp=&cbarray[Index*cbbysample+cbbysample-1];
cbp->info=cbp->info|(BCM2708_DMA_SET_INT);
*/
if(Started==false)
{
if(last_sample>buffersize/4)
{
start(); // 1/4 Fill buffer before starting DMA
Started=true;
}
}
return 0;
}

121
src/dma.h
View File

@@ -1,121 +0,0 @@
#ifndef DEF_DMA
#define DEF_DMA
#include "stdint.h"
#include "gpio.h"
// ---- Memory allocating defines
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
#define MEM_FLAG_DISCARDABLE (1 << 0) /* can be resized to 0 at any time. Use for cached data */
#define MEM_FLAG_NORMAL (0 << 2) /* normal allocating alias. Don't use from ARM */
#define MEM_FLAG_DIRECT (1 << 2) /* 0xC alias uncached */
#define MEM_FLAG_COHERENT (2 << 2) /* 0x8 alias. Non-allocating in L2 but coherent */
#define MEM_FLAG_L1_NONALLOCATING (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT) /* Allocating in L2 */
#define MEM_FLAG_ZERO ( 1 << 4) /* initialise buffer to all zeros */
#define MEM_FLAG_NO_INIT ( 1 << 5) /* don't initialise (default is initialise to all ones */
#define MEM_FLAG_HINT_PERMALOCK (1 << 6) /* Likely to be locked for long periods of time. */
#define BCM2708_DMA_SRC_IGNOR (1<<11)
#define BCM2708_DMA_SRC_INC (1<<8)
#define BCM2708_DMA_DST_IGNOR (1<<7)
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
#define BCM2708_DMA_WAIT_RESP (1<<3)
#define BCM2708_DMA_D_DREQ (1<<6)
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
#define BCM2708_DMA_END (1<<1)
#define BCM2708_DMA_RESET (1<<31)
#define BCM2708_DMA_INT (1<<2)
#define DMA_CS (0x00/4)
#define DMA_CONBLK_AD (0x04/4)
#define DMA_DEBUG (0x20/4)
//Page 61
#define DREQ_PCM_TX 2
#define DREQ_PCM_RX 3
#define DREQ_SMI 4
#define DREQ_PWM 5
#define DREQ_SPI_TX 6
#define DREQ_SPI_RX 7
#define DREQ_SPI_SLAVE_TX 8
#define DREQ_SPI_SLAVE_RX 9
class dma
{
protected:
struct {
int handle; /* From mbox_open() */
unsigned mem_ref; /* From mem_alloc() */
unsigned bus_addr; /* From mem_lock() */
uint8_t *virt_addr; /* From mapmem() */
} mbox;
typedef struct {
uint32_t info, src, dst, length,
stride, next, pad[2];
} dma_cb_t; //8*4=32 bytes
typedef struct {
uint8_t *virtaddr;
uint32_t physaddr;
} page_map_t;
page_map_t *page_map;
uint8_t *virtbase;
int NumPages=0;
int channel; //DMA Channel
dmagpio dma_reg;
uint32_t mem_flag; //Cache or not depending on Rpi1 or 2/3
uint32_t dram_phys_base;
public:
dma_cb_t *cbarray;
uint32_t cbsize;
uint32_t *usermem;
uint32_t usermemsize;
bool Started=false;
dma(int Channel,uint32_t CBSize,uint32_t UserMemSize);
~dma();
uint32_t mem_virt_to_phys(volatile void *virt);
uint32_t mem_phys_to_virt(volatile uint32_t phys);
void GetRpiInfo();
int start();
int stop();
int getcbposition();
bool isrunning();
bool isunderflow();
};
#define PHYSICAL_BUS 0x7E000000
class bufferdma:public dma
{
protected:
uint32_t current_sample;
uint32_t last_sample;
uint32_t sample_available;
public:
uint32_t buffersize;
uint32_t cbbysample;
uint32_t registerbysample;
uint32_t *sampletab;
public:
bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample);
void SetDmaAlgo();
int GetBufferAvailable();
int GetUserMemIndex();
int PushSample(int Index);
};
#endif

View File

@@ -1,68 +0,0 @@
#include "dsp.h"
dsp::dsp()
{
}
dsp::dsp(uint32_t srate):samplerate(srate)
{
}
#define ln(x) (log(x)/log(2.718281828459045235f))
// Again some functions taken gracefully from F4GKR : https://github.com/f4gkr/RadiantBee
//Normalize to [-180,180):
inline double dsp::constrainAngle(double x){
x = fmod(x + M_PI,2*M_PI);
if (x < 0)
x += 2*M_PI;
return x - M_PI;
}
// convert to [-360,360]
inline double dsp::angleConv(double angle){
return fmod(constrainAngle(angle),2*M_PI);
}
inline double dsp::angleDiff(double a,double b){
double dif = fmod(b - a + M_PI,2*M_PI);
if (dif < 0)
dif += 2*M_PI;
return dif - M_PI;
}
inline double dsp::unwrap(double previousAngle,double newAngle){
return previousAngle - angleDiff(newAngle,angleConv(previousAngle));
}
int dsp::arctan2(int y, int x) // Should be replaced with fast_atan2 from rtl_fm
{
int abs_y = abs(y);
int angle;
if((x==0)&&(y==0)) return 0;
if(x >= 0){
angle = 45 - 45 * (x - abs_y) / ((x + abs_y)==0?1:(x + abs_y));
} else {
angle = 135 - 45 * (x + abs_y) / ((abs_y - x)==0?1:(abs_y - x));
}
return (y < 0) ? -angle : angle; // negate if in quad III or IV
}
void dsp::pushsample(liquid_float_complex sample)
{
amplitude=norm(sample);
double phase=atan2(sample.imag(),sample.real());
//fprintf(stderr,"phase %f\n",phase);
phase=unwrap(prev_phase,phase);
double dp= phase-prev_phase;
frequency = (dp*(double)samplerate)/(2.0*M_PI);
prev_phase = phase;
}

View File

@@ -1,31 +0,0 @@
#ifndef DEF_DSP
#define DEF_DSP
#include "stdint.h"
#include <iostream>
#include <math.h>
#include <complex>
#include <liquid/liquid.h>
class dsp
{
protected:
double prev_phase = 0;
double constrainAngle(double x);
double angleConv(double angle);
double angleDiff(double a,double b);
double unwrap(double previousAngle,double newAngle);
int arctan2(int y, int x);
public:
uint32_t samplerate;
//double phase;
double amplitude;
double frequency;
dsp();
dsp(uint32_t samplerate);
void pushsample(liquid_float_complex sample);
};
#endif

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +0,0 @@
#include "stdio.h"
#include "fmdmasync.h"
#include "gpio.h" //for definition of registers
fmdmasync::fmdmasync(int Channel,uint32_t FifoSize):dma(Channel,FifoSize*2,FifoSize)
{
SetDmaAlgo();
FillMemory(12,1472);
}
fmdmasync::~fmdmasync()
{
}
void fmdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < cbsize/2; samplecnt++) { //cbsize/2 because we have 2 CB by sample
// Write a frequency sample
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt]);
cbp->dst = 0x7E000000 + (GPCLK_DIV<<2) + CLK_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
// Delay
cbp->info = /*BCM2708_DMA_SRC_IGNOR | */BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void fmdmasync::FillMemory(uint32_t FreqDivider,uint32_t FreqFractionnal)
{
for (uint32_t samplecnt = 0; samplecnt < usermemsize; samplecnt++)
{
usermem[samplecnt]=0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
FreqFractionnal=(FreqFractionnal+1)%4096;
if (FreqFractionnal==0) FreqDivider++;
}
}

View File

@@ -1,16 +0,0 @@
#ifndef DEF_FMDMASYNC
#define DEF_FMDMASYNC
#include "stdint.h"
#include "dma.h"
class fmdmasync:public dma
{
public:
fmdmasync(int Channel,uint32_t FifoSize);
~fmdmasync();
void SetDmaAlgo();
void FillMemory(uint32_t FreqDivider,uint32_t FreqFractionnal);
};
#endif

View File

@@ -1,114 +0,0 @@
#include "stdio.h"
#include "fskburst.h"
fskburst::fskburst(uint64_t TuneFrequency,uint32_t SymbolRate,uint32_t Deviation,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize+2,2,1),freqdeviation(Deviation)
{
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency,SymbolRate); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetFrequency(0);
//clkgpio::enableclk(4); // GPIO 4 CLK by default
syncwithpwm=false;
if(syncwithpwm)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SymbolRate);
}
else
{
pcmgpio::SetPllNumber(clk_plld,1);
pcmgpio::SetFrequency(SymbolRate);
}
SetDmaAlgo();
padgpio pad;
Originfsel=pad.gpioreg[PADS_GPIO_0];
}
fskburst::~fskburst()
{
}
void fskburst::SetDmaAlgo()
{
sampletab[buffersize*registerbysample-2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Enable Clk
sampletab[buffersize*registerbysample-1]=(Originfsel & ~(7 << 12)) | (0 << 12); //Disable Clk
dma_cb_t *cbp = cbarray;
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[buffersize*registerbysample-2]);
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1); // Stop DMA
cbp++;
for (uint32_t samplecnt = 0; samplecnt < buffersize-2; samplecnt++)
{
// Write a frequency sample
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
// Delay
if(syncwithpwm)
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
else
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
if(syncwithpwm)
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
else
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
lastcbp=cbp;
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[(buffersize*registerbysample-1)]);
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
cbp->length = 4;
cbp->stride = 0;
cbp->next = 0; // Stop DMA
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void fskburst::SetSymbols(unsigned char *Symbols,uint32_t Size)
{
if(Size>buffersize-2) {fprintf(stderr,"Buffer overflow\n");return;}
dma_cb_t *cbp=cbarray+1+1;
for(int i=0;i<Size;i++)
{
sampletab[i]=(0x5A<<24)|GetMasterFrac((Symbols[i]==0)?-freqdeviation:freqdeviation);
cbp = &cbarray[i*cbbysample+1+1];
cbp->next = mem_virt_to_phys(cbp + 1);
}
cbp->next = mem_virt_to_phys(lastcbp);
dma::start();
}

View File

@@ -1,23 +0,0 @@
#ifndef DEF_FSKBURST
#define DEF_FSKBURST
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class fskburst:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
{
protected:
uint32_t freqdeviation;
uint32_t Originfsel;
bool syncwithpwm;
dma_cb_t *lastcbp;
public:
fskburst(uint64_t TuneFrequency,uint32_t SymbolRate,uint32_t Deviation,int Channel,uint32_t FifoSize);
~fskburst();
void SetDmaAlgo();
void SetSymbols(unsigned char *Symbols,uint32_t Size);
};
#endif

View File

@@ -1,669 +0,0 @@
extern "C"
{
#include "mailbox.h"
}
#include "gpio.h"
#include "raspberry_pi_revision.h"
#include "stdio.h"
#include <unistd.h>
gpio::gpio(uint32_t base, uint32_t len)
{
gpioreg=( uint32_t *)mapmem(base,len);
}
uint32_t gpio::GetPeripheralBase()
{
RASPBERRY_PI_INFO_T info;
uint32_t BCM2708_PERI_BASE=0;
if (getRaspberryPiInformation(&info) > 0)
{
if(info.peripheralBase==RPI_BROADCOM_2835_PERIPHERAL_BASE)
{
BCM2708_PERI_BASE = info.peripheralBase ;
}
if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE))
{
BCM2708_PERI_BASE = info.peripheralBase ;
}
}
return BCM2708_PERI_BASE;
}
//******************** DMA Registers ***************************************
dmagpio::dmagpio():gpio(GetPeripheralBase()+DMA_BASE,DMA_LEN)
{
}
// ***************** CLK Registers *****************************************
clkgpio::clkgpio():gpio(GetPeripheralBase()+CLK_BASE,CLK_LEN)
{
}
clkgpio::~clkgpio()
{
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(0 << 4) ; //4 is START CLK
usleep(100);
}
int clkgpio::SetPllNumber(int PllNo,int MashType)
{
//print_clock_tree();
if(PllNo<8)
pllnumber=PllNo;
else
pllnumber=clk_pllc;
if(MashType<4)
Mash=MashType;
else
Mash=0;
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber/*|(1 << 5)*/ ; //5 is Reset CLK
usleep(100);
Pllfrequency=GetPllFrequency(pllnumber);
return 0;
}
uint64_t clkgpio::GetPllFrequency(int PllNo)
{
uint64_t Freq=0;
switch(PllNo)
{
case clk_osc:Freq=XOSC_FREQUENCY;break;
case clk_plla:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLA_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLA_FRAC]/(1<<20);break;
//case clk_pllb:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLB_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLB_FRAC]/(1<<20);break;
case clk_pllc:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLC_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLC_FRAC]/(1<<20);break;
case clk_plld:Freq=(XOSC_FREQUENCY*((uint64_t)gpioreg[PLLD_CTRL]&0x3ff) +(XOSC_FREQUENCY*(uint64_t)gpioreg[PLLD_FRAC])/(1<<20))/(gpioreg[PLLD_PER]>>1);break;
case clk_hdmi:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLH_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLH_FRAC]/(1<<20);break;
}
fprintf(stderr,"Freq = %lld\n",Freq);
return Freq;
}
int clkgpio::SetClkDivFrac(uint32_t Div,uint32_t Frac)
{
gpioreg[GPCLK_DIV] = 0x5A000000 | ((Div)<<12) | Frac;
usleep(100);
fprintf(stderr,"Clk Number %d div %d frac %d\n",pllnumber,Div,Frac);
//gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber |(1<<4) ; //4 is START CLK
// usleep(10);
return 0;
}
int clkgpio::SetMasterMultFrac(uint32_t Mult,uint32_t Frac)
{
fprintf(stderr,"Master Mult %d Frac %d\n",Mult,Frac);
gpioreg[PLLA_CTRL] = (0x5a<<24) | (0x21<<12) | Mult;
usleep(100);
gpioreg[PLLA_FRAC]= 0x5A000000 | Frac ;
return 0;
}
int clkgpio::SetFrequency(int Frequency)
{
if(ModulateFromMasterPLL)
{
double FloatMult=((double)(CentralFrequency+Frequency)*PllFixDivider)/(double)(XOSC_FREQUENCY);
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
freqctl&=0xFFFFF; // Fractionnal is 20bits
uint32_t FracMultiply=freqctl&0xFFFFF;
//gpioreg[PLLA_FRAC]= 0x5A000000 | FracMultiply ; // Only Frac is Sent
SetMasterMultFrac(IntMultiply,FracMultiply);
}
else
{
double Freqresult=(double)Pllfrequency/(double)(CentralFrequency+Frequency);
uint32_t FreqDivider=(uint32_t)Freqresult;
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
printf("DIV/FRAC %u/%u \n",FreqDivider,FreqFractionnal);
SetClkDivFrac(FreqDivider,FreqFractionnal);
}
return 0;
}
uint32_t clkgpio::GetMasterFrac(int Frequency)
{
if(ModulateFromMasterPLL)
{
double FloatMult=((double)(CentralFrequency+Frequency)*PllFixDivider)/(double)(XOSC_FREQUENCY);
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
freqctl&=0xFFFFF; // Fractionnal is 20bits
uint32_t FracMultiply=freqctl&0xFFFFF;
return FracMultiply;
}
else
return 0; //Not in Master CLk mode
}
int clkgpio::ComputeBestLO(uint64_t Frequency,int Bandwidth)
{
// Algorithm adapted from https://github.com/SaucySoliton/PiFmRds/blob/master/src/pi_fm_rds.c
// Choose an integer divider for GPCLK0
//
// There may be improvements possible to this algorithm.
double xtal_freq_recip=1.0/19.2e6; // todo PPM correction
int best_divider=0;
int solution_count=0;
//printf("carrier:%3.2f ",carrier_freq/1e6);
int divider,min_int_multiplier,max_int_multiplier, fom, int_multiplier, best_fom=0;
double frac_multiplier;
best_divider=0;
for( divider=1;divider<4096;divider++)
{
if( Frequency*divider < 600e6 ) continue; // widest accepted frequency range
if( Frequency*divider > 1800e6 ) break;
max_int_multiplier=((int)((double)(Frequency+Bandwidth)*divider*xtal_freq_recip));
min_int_multiplier=((int)((double)(Frequency-Bandwidth)*divider*xtal_freq_recip));
if( min_int_multiplier!=max_int_multiplier ) continue; // don't cross integer boundary
solution_count++; // if we make it here the solution is acceptable,
fom=0; // but we want a good solution
if( Frequency*divider > 900e6 ) fom++; // prefer freqs closer to 1000
if( Frequency*divider < 1100e6 ) fom++;
if( Frequency*divider > 800e6 ) fom++; // accepted frequency range
if( Frequency*divider < 1200e6 ) fom++;
frac_multiplier=((double)(Frequency)*divider*xtal_freq_recip);
int_multiplier = (int) frac_multiplier;
frac_multiplier = frac_multiplier - int_multiplier;
if((int_multiplier%2)==0) fom++;
if( (frac_multiplier>0.4) && (frac_multiplier<0.6) ) fom+=2; // prefer mulipliers away from integer boundaries
//if( divider%2 == 1 ) fom+=2; // prefer odd dividers
// Even and odd dividers could have different harmonic content,
// but the latest measurements have shown no significant difference.
//printf(" multiplier:%f divider:%d VCO: %4.1fMHz\n",carrier_freq*divider*xtal_freq_recip,divider,(double)carrier_freq*divider/1e6);
if( fom > best_fom )
{
best_fom=fom;
best_divider=divider;
}
}
if(solution_count>0)
{
PllFixDivider=best_divider;
fprintf(stderr," multiplier:%f divider:%d VCO: %4.1fMHz\n",Frequency*best_divider*xtal_freq_recip,best_divider,(double)Frequency*best_divider/1e6);
return 0;
}
else
{
fprintf(stderr,"Central frequency not available !!!!!!\n");
return -1;
}
}
int clkgpio::SetCenterFrequency(uint64_t Frequency,int Bandwidth)
{
CentralFrequency=Frequency;
if(ModulateFromMasterPLL)
{
//Choose best PLLDiv and Div
ComputeBestLO(Frequency,Bandwidth); //FixeDivider update
SetFrequency(0);
usleep(1000);
if((gpioreg[CM_LOCK]&CM_LOCK_FLOCKA)>0)
fprintf(stderr,"Master PLLA Locked\n");
else
fprintf(stderr,"Warning ! Master PLLA NOT Locked !!!!\n");
SetClkDivFrac(PllFixDivider,0); // NO MASH !!!!
usleep(100);
usleep(100);
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
}
else
{
GetPllFrequency(pllnumber);// Be sure to get the master PLL frequency
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
}
return 0;
}
void clkgpio::SetPhase(bool inversed)
{
uint32_t StateBefore=clkgpio::gpioreg[GPCLK_CNTL];
clkgpio::gpioreg[GPCLK_CNTL]= (0x5A<<24) | StateBefore | ((inversed?1:0)<<8) | 1<<5;
clkgpio::gpioreg[GPCLK_CNTL]= (0x5A<<24) | StateBefore | ((inversed?1:0)<<8) | 0<<5;
}
void clkgpio::SetAdvancedPllMode(bool Advanced)
{
ModulateFromMasterPLL=Advanced;
if(ModulateFromMasterPLL)
{
SetPllNumber(clk_plla,0); // Use PPL_A , Do not USE MASH which generates spurious
gpioreg[0x104/4]=0x5A00020A; // Enable Plla_PER
usleep(100);
uint32_t ana[4];
for(int i=3;i>=0;i--)
{
ana[i]=gpioreg[(0x1010/4)+i];
}
//ana[1]&=~(1<<14); // No use prediv means Frequency
ana[1]|=(1<<14); // use prediv means Frequency*2
for(int i=3;i>=0;i--)
{
gpioreg[(0x1010/4)+i]=(0x5A<<24)|ana[i];
}
usleep(100);
gpioreg[PLLA_PER]=0x5A000002; // Div ?
usleep(100);
}
}
void clkgpio::print_clock_tree(void)
{
printf("PLLC_DIG0=%08x\n",gpioreg[(0x1020/4)]);
printf("PLLC_DIG1=%08x\n",gpioreg[(0x1024/4)]);
printf("PLLC_DIG2=%08x\n",gpioreg[(0x1028/4)]);
printf("PLLC_DIG3=%08x\n",gpioreg[(0x102c/4)]);
printf("PLLC_ANA0=%08x\n",gpioreg[(0x1030/4)]);
printf("PLLC_ANA1=%08x\n",gpioreg[(0x1034/4)]);
printf("PLLC_ANA2=%08x\n",gpioreg[(0x1038/4)]);
printf("PLLC_ANA3=%08x\n",gpioreg[(0x103c/4)]);
printf("PLLC_DIG0R=%08x\n",gpioreg[(0x1820/4)]);
printf("PLLC_DIG1R=%08x\n",gpioreg[(0x1824/4)]);
printf("PLLC_DIG2R=%08x\n",gpioreg[(0x1828/4)]);
printf("PLLC_DIG3R=%08x\n",gpioreg[(0x182c/4)]);
printf("PLLA_ANA0=%08x\n",gpioreg[(0x1010/4)]);
printf("PLLA_ANA1=%08x prediv=%d\n",gpioreg[(0x1014/4)],(gpioreg[(0x1014/4)]>>14)&1);
printf("PLLA_ANA2=%08x\n",gpioreg[(0x1018/4)]);
printf("PLLA_ANA3=%08x\n",gpioreg[(0x101c/4)]);
printf("GNRIC CTL=%08x DIV=%8x ",gpioreg[ 0],gpioreg[ 1]);
printf("VPU CTL=%08x DIV=%8x\n",gpioreg[ 2],gpioreg[ 3]);
printf("SYS CTL=%08x DIV=%8x ",gpioreg[ 4],gpioreg[ 5]);
printf("PERIA CTL=%08x DIV=%8x\n",gpioreg[ 6],gpioreg[ 7]);
printf("PERII CTL=%08x DIV=%8x ",gpioreg[ 8],gpioreg[ 9]);
printf("H264 CTL=%08x DIV=%8x\n",gpioreg[10],gpioreg[11]);
printf("ISP CTL=%08x DIV=%8x ",gpioreg[12],gpioreg[13]);
printf("V3D CTL=%08x DIV=%8x\n",gpioreg[14],gpioreg[15]);
printf("CAM0 CTL=%08x DIV=%8x ",gpioreg[16],gpioreg[17]);
printf("CAM1 CTL=%08x DIV=%8x\n",gpioreg[18],gpioreg[19]);
printf("CCP2 CTL=%08x DIV=%8x ",gpioreg[20],gpioreg[21]);
printf("DSI0E CTL=%08x DIV=%8x\n",gpioreg[22],gpioreg[23]);
printf("DSI0P CTL=%08x DIV=%8x ",gpioreg[24],gpioreg[25]);
printf("DPI CTL=%08x DIV=%8x\n",gpioreg[26],gpioreg[27]);
printf("GP0 CTL=%08x DIV=%8x ",gpioreg[0x70/4],gpioreg[0x74/4]);
printf("GP1 CTL=%08x DIV=%8x\n",gpioreg[30],gpioreg[31]);
printf("GP2 CTL=%08x DIV=%8x ",gpioreg[32],gpioreg[33]);
printf("HSM CTL=%08x DIV=%8x\n",gpioreg[34],gpioreg[35]);
printf("OTP CTL=%08x DIV=%8x ",gpioreg[36],gpioreg[37]);
printf("PCM CTL=%08x DIV=%8x\n",gpioreg[38],gpioreg[39]);
printf("PWM CTL=%08x DIV=%8x ",gpioreg[40],gpioreg[41]);
printf("SLIM CTL=%08x DIV=%8x\n",gpioreg[42],gpioreg[43]);
printf("SMI CTL=%08x DIV=%8x ",gpioreg[44],gpioreg[45]);
printf("SMPS CTL=%08x DIV=%8x\n",gpioreg[46],gpioreg[47]);
printf("TCNT CTL=%08x DIV=%8x ",gpioreg[48],gpioreg[49]);
printf("TEC CTL=%08x DIV=%8x\n",gpioreg[50],gpioreg[51]);
printf("TD0 CTL=%08x DIV=%8x ",gpioreg[52],gpioreg[53]);
printf("TD1 CTL=%08x DIV=%8x\n",gpioreg[54],gpioreg[55]);
printf("TSENS CTL=%08x DIV=%8x ",gpioreg[56],gpioreg[57]);
printf("TIMER CTL=%08x DIV=%8x\n",gpioreg[58],gpioreg[59]);
printf("UART CTL=%08x DIV=%8x ",gpioreg[60],gpioreg[61]);
printf("VEC CTL=%08x DIV=%8x\n",gpioreg[62],gpioreg[63]);
printf("PULSE CTL=%08x DIV=%8x ",gpioreg[100],gpioreg[101]);
printf("PLLT CTL=%08x DIV=????????\n",gpioreg[76]);
printf("DSI1E CTL=%08x DIV=%8x ",gpioreg[86],gpioreg[87]);
printf("DSI1P CTL=%08x DIV=%8x\n",gpioreg[88],gpioreg[89]);
printf("AVE0 CTL=%08x DIV=%8x\n",gpioreg[90],gpioreg[91]);
printf("CMPLLA=%08x ",gpioreg[0x104/4]);
printf("CMPLLC=%08x \n",gpioreg[0x108/4]);
printf("CMPLLD=%08x ",gpioreg[0x10C/4]);
printf("CMPLLH=%08x \n",gpioreg[0x110/4]);
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
// Sometimes calculated frequencies are off by a factor of 2
// ANA1 bit 14 may indicate that a /2 prescaler is active
printf("PLLA PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLA_CTRL]>>16) ,gpioreg[PLLA_CTRL]&0x3ff, gpioreg[PLLA_FRAC] );
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLA_CTRL]&0x3ff) + ((float)gpioreg[PLLA_FRAC])/((float)(1<<20))) );
printf("DSI0=%d CORE=%d PER=%d CCP2=%d\n\n",gpioreg[PLLA_DSI0],gpioreg[PLLA_CORE],gpioreg[PLLA_PER],gpioreg[PLLA_CCP2]);
printf("PLLB PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLB_CTRL]>>16) ,gpioreg[PLLB_CTRL]&0x3ff, gpioreg[PLLB_FRAC] );
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLB_CTRL]&0x3ff) + ((float)gpioreg[PLLB_FRAC])/((float)(1<<20))) );
printf("ARM=%d SP0=%d SP1=%d SP2=%d\n\n",gpioreg[PLLB_ARM],gpioreg[PLLB_SP0],gpioreg[PLLB_SP1],gpioreg[PLLB_SP2]);
printf("PLLC PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLC_CTRL]>>16) ,gpioreg[PLLC_CTRL]&0x3ff, gpioreg[PLLC_FRAC] );
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLC_CTRL]&0x3ff) + ((float)gpioreg[PLLC_FRAC])/((float)(1<<20))) );
printf("CORE2=%d CORE1=%d PER=%d CORE0=%d\n\n",gpioreg[PLLC_CORE2],gpioreg[PLLC_CORE1],gpioreg[PLLC_PER],gpioreg[PLLC_CORE0]);
printf("PLLD %x PDIV=%d NDIV=%d FRAC=%d ",gpioreg[PLLD_CTRL],(gpioreg[PLLD_CTRL]>>16) ,gpioreg[PLLD_CTRL]&0x3ff, gpioreg[PLLD_FRAC] );
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLD_CTRL]&0x3ff) + ((float)gpioreg[PLLD_FRAC])/((float)(1<<20))) );
printf("DSI0=%d CORE=%d PER=%d DSI1=%d\n\n",gpioreg[PLLD_DSI0],gpioreg[PLLD_CORE],gpioreg[PLLD_PER],gpioreg[PLLD_DSI1]);
printf("PLLH PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLH_CTRL]>>16) ,gpioreg[PLLH_CTRL]&0x3ff, gpioreg[PLLH_FRAC] );
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLH_CTRL]&0x3ff) + ((float)gpioreg[PLLH_FRAC])/((float)(1<<20))) );
printf("AUX=%d RCAL=%d PIX=%d STS=%d\n\n",gpioreg[PLLH_AUX],gpioreg[PLLH_RCAL],gpioreg[PLLH_PIX],gpioreg[PLLH_STS]);
}
void clkgpio::enableclk(int gpio)
{
switch(gpio)
{
case 4: gengpio.setmode(gpio,fsel_alt0);break;
case 20:gengpio.setmode(gpio,fsel_alt5);break;
case 32:gengpio.setmode(gpio,fsel_alt0);break;
case 34:gengpio.setmode(gpio,fsel_alt0);break;
default: fprintf(stderr,"gpio %d has no clk - available(4,20,32,34)\n",gpio);break;
}
usleep(100);
}
void clkgpio::disableclk(int gpio)
{
gengpio.setmode(gpio,fsel_input);
}
// ************************************** GENERAL GPIO *****************************************************
generalgpio::generalgpio():gpio(GetPeripheralBase()+GENERAL_BASE,GENERAL_LEN)
{
}
generalgpio::~generalgpio()
{
}
int generalgpio::setmode(uint32_t gpio, uint32_t mode)
{
int reg, shift;
reg = gpio/10;
shift = (gpio%10) * 3;
gpioreg[reg] = (gpioreg[reg] & ~(7<<shift)) | (mode<<shift);
return 0;
}
// ********************************** PWM GPIO **********************************
pwmgpio::pwmgpio():gpio(GetPeripheralBase()+PWM_BASE,PWM_LEN)
{
gpioreg[PWM_CTL] = 0;
}
pwmgpio::~pwmgpio()
{
gpioreg[PWM_CTL] = 0;
gpioreg[PWM_DMAC] = 0;
}
void pwmgpio::enablepwm(int gpio,int PwmNumber)
{
if(PwmNumber==0)
{
switch(gpio)
{
case 12:gengpio.setmode(gpio,fsel_alt0);break;
case 18:gengpio.setmode(gpio,fsel_alt5);break;
case 40:gengpio.setmode(gpio,fsel_alt0);break;
default: fprintf(stderr,"gpio %d has no pwm - available(12,18,40)\n",gpio);break;
}
}
if(PwmNumber==1)
{
switch(gpio)
{
case 13:gengpio.setmode(gpio,fsel_alt0);break;
case 19:gengpio.setmode(gpio,fsel_alt5);break;
case 41:gengpio.setmode(gpio,fsel_alt0);break;
case 45:gengpio.setmode(gpio,fsel_alt0);break;
default: fprintf(stderr,"gpio %d has no pwm - available(13,19,41,45)\n",gpio);break;
}
}
usleep(100);
}
void pwmgpio::disablepwm(int gpio)
{
gengpio.setmode(gpio,fsel_input);
}
int pwmgpio::SetPllNumber(int PllNo,int MashType)
{
if(PllNo<8)
pllnumber=PllNo;
else
pllnumber=clk_pllc;
if(MashType<4)
Mash=MashType;
else
Mash=0;
clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(0 << 4) ; //4 is STOP CLK
usleep(100);
Pllfrequency=GetPllFrequency(pllnumber);
return 0;
}
uint64_t pwmgpio::GetPllFrequency(int PllNo)
{
return clk.GetPllFrequency(PllNo);
}
int pwmgpio::SetFrequency(uint64_t Frequency)
{
Prediv=32; // Fixe for now , need investigation if not 32 !!!! FixMe !
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
uint32_t FreqDivider=(uint32_t)Freqresult;
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
fprintf(stderr,"PWM clk=%d / %d\n",FreqDivider,FreqFractionnal);
clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
usleep(100);
clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is STAR CLK
usleep(100);
SetPrediv(Prediv); //SetMode should be called before
return 0;
}
void pwmgpio::SetMode(int Mode)
{
if((Mode>=pwm1pin)&&(Mode<=pwm1pinrepeat))
ModePwm=Mode;
}
int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data serializer : Todo
{
Prediv=predivisor;
if(Prediv>32)
{
fprintf(stderr,"PWM Prediv is max 32\n");
Prediv=2;
}
fprintf(stderr,"PWM Prediv %d\n",Prediv);
gpioreg[PWM_RNG1] = Prediv;// 250 -> 8KHZ
usleep(100);
gpioreg[PWM_RNG2] = Prediv;// 32 Mandatory for Serial Mode without gap
//gpioreg[PWM_FIFO]=0xAAAAAAAA;
gpioreg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
usleep(100);
gpioreg[PWM_CTL] = PWMCTL_CLRF;
usleep(100);
//gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
switch(ModePwm)
{
case pwm1pin:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;break; // All serial go to 1 pin
case pwm2pin:gpioreg[PWM_CTL] = PWMCTL_USEF2|PWMCTL_PWEN2|PWMCTL_MODE2|PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1;break;// Alternate bit to pin 1 and 2
case pwm1pinrepeat:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_RPTL1;break; // All serial go to 1 pin, repeat if empty : RF mode with PWM
}
usleep(100);
return 0;
}
// ********************************** PCM GPIO (I2S) **********************************
pcmgpio::pcmgpio():gpio(GetPeripheralBase()+PCM_BASE,PCM_LEN)
{
gpioreg[PCM_CS_A] = 1; // Disable Rx+Tx, Enable PCM block
}
pcmgpio::~pcmgpio()
{
}
int pcmgpio::SetPllNumber(int PllNo,int MashType)
{
if(PllNo<8)
pllnumber=PllNo;
else
pllnumber=clk_pllc;
if(MashType<4)
Mash=MashType;
else
Mash=0;
clk.gpioreg[PCMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
Pllfrequency=GetPllFrequency(pllnumber);
return 0;
}
uint64_t pcmgpio::GetPllFrequency(int PllNo)
{
return clk.GetPllFrequency(PllNo);
}
int pcmgpio::ComputePrediv(uint64_t Frequency)
{
int prediv=5;
for(prediv=10;prediv<1000;prediv++)
{
double Freqresult=(double)Pllfrequency/(double)(Frequency*prediv);
if((Freqresult<4096.0)&&(Freqresult>2.0))
{
fprintf(stderr,"PCM prediv = %d\n",prediv);
break;
}
}
return prediv;
}
int pcmgpio::SetFrequency(uint64_t Frequency)
{
Prediv=ComputePrediv(Frequency);
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
uint32_t FreqDivider=(uint32_t)Freqresult;
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
fprintf(stderr,"PCM clk=%d / %d\n",FreqDivider,FreqFractionnal);
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"PCM Frequency out of range\n");
clk.gpioreg[PCMCLK_DIV] = 0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
SetPrediv(Prediv);
return 0;
}
int pcmgpio::SetPrediv(int predivisor) //Carefull we use a 10 fixe divisor for now : frequency is thus f/10 as a samplerate
{
if(predivisor>1000)
{
fprintf(stderr,"PCM prediv should be <1000");
predivisor=1000;
}
gpioreg[PCM_TXC_A] = 0<<31 | 1<<30 | 0<<20 | 0<<16; // 1 channel, 8 bits
usleep(100);
//printf("Nb PCM STEP (<1000):%d\n",NbStepPCM);
gpioreg[PCM_MODE_A] = (predivisor-1)<<10; // SHOULD NOT EXCEED 1000 !!!
usleep(100);
gpioreg[PCM_CS_A] |= 1<<4 | 1<<3; // Clear FIFOs
usleep(100);
gpioreg[PCM_DREQ_A] = 64<<24 | 64<<8 ; //TX Fifo PCM=64 DMA Req when one slot is free?
usleep(100);
gpioreg[PCM_CS_A] |= 1<<9; // Enable DMA
usleep(100);
gpioreg[PCM_CS_A] |= 1<<2; //START TX PCM
return 0;
}
// ********************************** PADGPIO (Amplitude) **********************************
padgpio::padgpio():gpio(GetPeripheralBase()+PADS_GPIO,PADS_GPIO_LEN)
{
}
padgpio::~padgpio()
{
}

View File

@@ -1,284 +0,0 @@
#ifndef DEF_GPIO
#define DEF_GPIO
#include "stdint.h"
class gpio
{
public:
volatile uint32_t *gpioreg;
gpio(uint32_t base, uint32_t len);
uint32_t GetPeripheralBase();
};
#define DMA_BASE (0x00007000 )
#define DMA_LEN 0xF00
#define BCM2708_DMA_SRC_IGNOR (1<<11)
#define BCM2708_DMA_SRC_INC (1<<8)
#define BCM2708_DMA_DST_IGNOR (1<<7)
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
#define BCM2708_DMA_WAIT_RESP (1<<3)
#define BCM2708_DMA_SET_INT (1<<0)
#define BCM2708_DMA_D_DREQ (1<<6)
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
#define BCM2708_DMA_END (1<<1)
#define BCM2708_DMA_RESET (1<<31)
#define BCM2708_DMA_ABORT (1<<30)
#define BCM2708_DMA_INT (1<<2)
#define DMA_CS (0x00/4)
#define DMA_CONBLK_AD (0x04/4)
#define DMA_DEBUG (0x20/4)
#define DMA_CS_RESET (1<<31)
#define DMA_CS_ABORT (1<<30)
#define DMA_CS_DISDEBUG (1<<28)
#define DMA_CS_INT (1<<2)
#define DMA_CS_END (1<<1)
#define DMA_CS_ACTIVE (1<<0)
#define DMA_CS_PRIORITY(x) ((x)&0xf << 16)
#define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20)
class dmagpio:public gpio
{
public:
dmagpio();
};
//************************************ GENERAL GPIO ***************************************
#define GENERAL_BASE (0x00200000)
#define GENERAL_LEN 0xB4
#define GPFSEL0 (0x00/4)
#define GPFSEL1 (0x04/4)
#define GPFSEL2 (0x08/4)
#define GPPUD (0x94/4)
#define GPPUDCLK0 (0x9C/4)
enum {fsel_input,fsel_output,fsel_alt5,fsel_alt4,fsel_alt0,fsel_alt1,fsel_alt2,fsel_alt3};
class generalgpio:public gpio
{
public:
generalgpio();
int setmode(uint32_t gpio, uint32_t mode);
~generalgpio();
};
// Add for PLL frequency CTRL wihout divider
// https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/clk/bcm/clk-bcm2835.c
// See interesting patch for jitter https://github.com/raspberrypi/linux/commit/76527b4e6a5dbe55e0b2d8ab533c2388b36c86be
#define CLK_BASE (0x00101000)
#define CLK_LEN 0x1300
#define CORECLK_CNTL (0x08/4)
#define CORECLK_DIV (0x0c/4)
#define GPCLK_CNTL (0x70/4)
#define GPCLK_DIV (0x74/4)
#define EMMCCLK_CNTL (0x1C0/4)
#define EMMCCLK_DIV (0x1C4/4)
#define CM_LOCK (0x114/4)
# define CM_LOCK_FLOCKH (1<<12)
# define CM_LOCK_FLOCKD (1<<11)
# define CM_LOCK_FLOCKC (1<<10)
# define CM_LOCK_FLOCKB (1<<9)
# define CM_LOCK_FLOCKA (1<<8)
#define PLLA_CTRL (0x1100/4)
#define PLLA_FRAC (0x1200/4)
#define PLLA_DSI0 (0x1300/4)
#define PLLA_CORE (0x1400/4)
#define PLLA_PER (0x1500/4)
#define PLLA_CCP2 (0x1600/4)
#define PLLB_CTRL (0x11e0/4)
#define PLLB_FRAC (0x12e0/4)
#define PLLB_ARM (0x13e0/4)
#define PLLB_SP0 (0x14e0/4)
#define PLLB_SP1 (0x15e0/4)
#define PLLB_SP2 (0x16e0/4)
#define PLLC_CTRL (0x1120/4)
#define PLLC_FRAC (0x1220/4)
#define PLLC_CORE2 (0x1320/4)
#define PLLC_CORE1 (0x1420/4)
#define PLLC_PER (0x1520/4)
#define PLLC_CORE0 (0x1620/4)
#define PLLD_CTRL (0x1140/4)
#define PLLD_FRAC (0x1240/4)
#define PLLD_DSI0 (0x1340/4)
#define PLLD_CORE (0x1440/4)
#define PLLD_PER (0x1540/4)
#define PLLD_DSI1 (0x1640/4)
#define PLLH_CTRL (0x1160/4)
#define PLLH_FRAC (0x1260/4)
#define PLLH_AUX (0x1360/4)
#define PLLH_RCAL (0x1460/4)
#define PLLH_PIX (0x1560/4)
#define PLLH_STS (0x1660/4)
#define XOSC_CTRL (0x1190/4)
#define XOSC_FREQUENCY 19200000
enum {clk_gnd,clk_osc,clk_debug0,clk_debug1,clk_plla,clk_pllc,clk_plld,clk_hdmi};
class clkgpio:public gpio
{
protected:
int pllnumber;
int Mash;
uint64_t Pllfrequency;
bool ModulateFromMasterPLL=false;
uint64_t CentralFrequency=0;
generalgpio gengpio;
public:
int PllFixDivider=8; //Fix divider from the master clock in advanced mode
clkgpio();
~clkgpio();
int SetPllNumber(int PllNo,int MashType);
uint64_t GetPllFrequency(int PllNo);
void print_clock_tree(void);
int SetFrequency(int Frequency);
int SetClkDivFrac(uint32_t Div,uint32_t Frac);
void SetPhase(bool inversed);
void SetAdvancedPllMode(bool Advanced);
int SetCenterFrequency(uint64_t Frequency,int Bandwidth);
int ComputeBestLO(uint64_t Frequency,int Bandwidth);
int SetMasterMultFrac(uint32_t Mult,uint32_t Frac);
uint32_t GetMasterFrac(int Frequency);
void enableclk(int gpio);
void disableclk(int gpio);
};
//************************************ PWM GPIO ***************************************
#define PWM_BASE (0x0020C000)
#define PWM_LEN 0x28
#define PWM_CTL (0x00/4)
#define PWM_DMAC (0x08/4)
#define PWM_RNG1 (0x10/4)
#define PWM_RNG2 (0x20/4)
#define PWM_FIFO (0x18/4)
#define PWMCLK_CNTL (40) // Clk register
#define PWMCLK_DIV (41) // Clk register
#define PWMCTL_MSEN2 (1<<15)
#define PWMCTL_USEF2 (1<<13)
#define PWMCTL_RPTL2 (1<<10)
#define PWMCTL_MODE2 (1<<9)
#define PWMCTL_PWEN2 (1<<8)
#define PWMCTL_MSEN1 (1<<7)
#define PWMCTL_CLRF (1<<6)
#define PWMCTL_USEF1 (1<<5)
#define PWMCTL_POLA1 (1<<4)
#define PWMCTL_RPTL1 (1<<2)
#define PWMCTL_MODE1 (1<<1)
#define PWMCTL_PWEN1 (1<<0)
#define PWMDMAC_ENAB (1<<31)
#define PWMDMAC_THRSHLD ((15<<8)|(15<<0))
enum pwmmode{pwm1pin,pwm2pin,pwm1pinrepeat};
class pwmgpio:public gpio
{
protected:
clkgpio clk;
int pllnumber;
int Mash;
int Prediv; //Range of PWM
uint64_t Pllfrequency;
bool ModulateFromMasterPLL=false;
int ModePwm=pwm1pin;
generalgpio gengpio;
public:
pwmgpio();
~pwmgpio();
int SetPllNumber(int PllNo,int MashType);
uint64_t GetPllFrequency(int PllNo);
int SetFrequency(uint64_t Frequency);
int SetPrediv(int predivisor);
void SetMode(int Mode);
void enablepwm(int gpio,int PwmNumber);
void disablepwm(int gpio);
};
//******************************* PCM GPIO (I2S) ***********************************
#define PCM_BASE (0x00203000)
#define PCM_LEN 0x24
#define PCM_CS_A (0x00/4)
#define PCM_FIFO_A (0x04/4)
#define PCM_MODE_A (0x08/4)
#define PCM_RXC_A (0x0c/4)
#define PCM_TXC_A (0x10/4)
#define PCM_DREQ_A (0x14/4)
#define PCM_INTEN_A (0x18/4)
#define PCM_INT_STC_A (0x1c/4)
#define PCM_GRAY (0x20/4)
#define PCMCLK_CNTL (38) // Clk register
#define PCMCLK_DIV (39) // Clk register
class pcmgpio:public gpio
{
protected:
clkgpio clk;
int pllnumber;
int Mash;
int Prediv; //Range of PCM
uint64_t Pllfrequency;
int SetPrediv(int predivisor);
public:
pcmgpio();
~pcmgpio();
int SetPllNumber(int PllNo,int MashType);
uint64_t GetPllFrequency(int PllNo);
int SetFrequency(uint64_t Frequency);
int ComputePrediv(uint64_t Frequency);
};
//******************************* PAD GPIO (Amplitude) ***********************************
#define PADS_GPIO (0x00100000)
#define PADS_GPIO_LEN (0x40/4)
#define PADS_GPIO_0 (0x2C/4)
#define PADS_GPIO_1 (0x30/4)
#define PADS_GPIO_2 (0x34/4)
class padgpio:public gpio
{
public:
padgpio();
~padgpio();
};
#endif

View File

@@ -1,149 +0,0 @@
// Inspired by https://github.com/SaucySoliton/PiFmRds/blob/master/src/pi_fm_rds.c
#include "stdio.h"
#include "iqdmasync.h"
iqdmasync::iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,4,3)
{
// Usermem :
// FRAC frequency
// PAD Amplitude
// FSEL for amplitude 0
tunefreq=TuneFrequency;
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetFrequency(0);
clkgpio::enableclk(4);
syncwithpwm=false;
if(syncwithpwm)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SampleRate);
}
else
{
pcmgpio::SetPllNumber(clk_plld,1);
pcmgpio::SetFrequency(SampleRate);
}
mydsp.samplerate=SampleRate;
padgpio pad;
Originfsel=pad.gpioreg[PADS_GPIO_0];
SetDmaAlgo();
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
}
iqdmasync::~iqdmasync()
{
padgpio pad;
pad.gpioreg[PADS_GPIO_0]=Originfsel;
clkgpio::disableclk(4);
}
void iqdmasync::SetPhase(bool inversed)
{
clkgpio::SetPhase(inversed);
}
void iqdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
//@0
//Set Amplitude by writing to PADS
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]);
cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
cbp++;
//@1
//Set Amplitude to FSEL for amplitude=0
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+2]);
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
cbp++;
//@2 Write a frequency sample
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
//@3 Delay
if(syncwithpwm)
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
else
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
if(syncwithpwm)
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
else
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void iqdmasync::SetIQSample(uint32_t Index,liquid_float_complex sample)
{
Index=Index%buffersize;
mydsp.pushsample(sample);
/*if(mydsp.frequency>2250) mydsp.frequency=2250;
if(mydsp.frequency<1000) mydsp.frequency=1000;*/
sampletab[Index*registerbysample]=(0x5A<<24)|GetMasterFrac(mydsp.frequency); //Frequency
int IntAmplitude=(int)(mydsp.amplitude*1e4*8.0)-1;
int IntAmplitudePAD=0;
if(IntAmplitude>7) IntAmplitudePAD=7;
if(IntAmplitude<0) IntAmplitudePAD=0;
sampletab[Index*registerbysample+1]=(0x5A<<24) + (IntAmplitudePAD&0x7) + (1<<4) + (0<<3); // Amplitude PAD
//sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
if(IntAmplitude==-1)
{
sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (0 << 12); //Pin is in -> Amplitude 0
}
else
{
sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
}
//fprintf(stderr,"amp%f %d\n",mydsp.amplitude,IntAmplitudePAD);
PushSample(Index);
}

View File

@@ -1,27 +0,0 @@
#ifndef DEF_IQDMASYNC
#define DEF_IQDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
#include "dsp.h"
#include <liquid/liquid.h>
class iqdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
{
protected:
uint64_t tunefreq;
bool syncwithpwm;
dsp mydsp;
uint32_t Originfsel; //Save the original FSEL GPIO
public:
iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
~iqdmasync();
void SetDmaAlgo();
void SetPhase(bool inversed);
void SetIQSample(uint32_t Index,liquid_float_complex sample);
};
#endif

View File

@@ -1,10 +0,0 @@
#include "dma.h"
#include "gpio.h"
#include "fmdmasync.h"
#include "ngfmdmasync.h"
#include "iqdmasync.h"
#include "serialdmasync.h"
#include "phasedmasync.h"
#include "amdmasync.h"
#include "fskburst.h"
#include "dsp.h"

View File

@@ -1,280 +0,0 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "mailbox.h"
void *mapmem(unsigned base, unsigned size)
{
int mem_fd;
unsigned offset = base % PAGE_SIZE;
base = base - offset;
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n");
exit (-1);
}
void *mem = mmap(
0,
size,
PROT_READ|PROT_WRITE,
MAP_SHARED/*|MAP_FIXED*/,
mem_fd,
base);
#ifdef DEBUG
printf("base=0x%x, mem=%p\n", base, mem);
#endif
if (mem == MAP_FAILED) {
printf("mmap error %d\n", (int)mem);
exit (-1);
}
close(mem_fd);
return (char *)mem + offset;
}
void *unmapmem(void *addr, unsigned size)
{
int s = munmap(addr, size);
if (s != 0) {
printf("munmap error %d\n", s);
exit (-1);
}
return NULL;
}
/*
* use ioctl to send mbox property message
*/
static int mbox_property(int file_desc, void *buf)
{
int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
if (ret_val < 0) {
printf("ioctl_set_msg failed:%d\n", ret_val);
}
#ifdef DEBUG
unsigned *p = buf; int i; unsigned size = *(unsigned *)buf;
for (i=0; i<size/4; i++)
printf("%04x: 0x%08x\n", i*sizeof *p, p[i]);
#endif
return ret_val;
}
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags)
{
int i=0;
unsigned p[32];
//printf("Requesting %d bytes\n", size);
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x3000c; // (the tag id)
p[i++] = 12; // (size of the buffer)
p[i++] = 12; // (size of the data)
p[i++] = size; // (num bytes? or pages?)
p[i++] = align; // (alignment)
p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING)
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned mem_free(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x3000f; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned mem_lock(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x3000d; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned mem_unlock(int file_desc, unsigned handle)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x3000e; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = handle;
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x30010; // (the tag id)
p[i++] = 28; // (size of the buffer)
p[i++] = 28; // (size of the data)
p[i++] = code;
p[i++] = r0;
p[i++] = r1;
p[i++] = r2;
p[i++] = r3;
p[i++] = r4;
p[i++] = r5;
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned qpu_enable(int file_desc, unsigned enable)
{
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x30012; // (the tag id)
p[i++] = 4; // (size of the buffer)
p[i++] = 4; // (size of the data)
p[i++] = enable;
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout) {
int i=0;
unsigned p[32];
p[i++] = 0; // size
p[i++] = 0x00000000; // process request
p[i++] = 0x30011; // (the tag id)
p[i++] = 16; // (size of the buffer)
p[i++] = 16; // (size of the data)
p[i++] = num_qpus;
p[i++] = control;
p[i++] = noflush;
p[i++] = timeout; // ms
p[i++] = 0x00000000; // end tag
p[0] = i*sizeof *p; // actual size
mbox_property(file_desc, p);
return p[5];
}
int mbox_open() {
int file_desc;
// Open a char device file used for communicating with kernel mbox driver.
file_desc = open(VCIO_DEVICE_FILE_NAME, 0);
if(file_desc >= 0) {
printf("Using mbox device " VCIO_DEVICE_FILE_NAME ".\n");
return file_desc;
}
// Try to create one
unlink(LOCAL_DEVICE_FILE_NAME);
if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_A, 0)) >= 0 &&
(file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) {
printf("Using local mbox device file with major %d.\n", MAJOR_NUM_A);
return file_desc;
}
unlink(LOCAL_DEVICE_FILE_NAME);
if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_B, 0)) >= 0 &&
(file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) {
printf("Using local mbox device file with major %d.\n", MAJOR_NUM_B);
return file_desc;
}
return file_desc;
}
void mbox_close(int file_desc) {
close(file_desc);
}

View File

@@ -1,56 +0,0 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DEF_MAILBOX
#include <linux/ioctl.h>
// Newer kernels (>= 4.1) use major 249, older ones major 100.
#define MAJOR_NUM_A 249
#define MAJOR_NUM_B 100
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM_B, 0, char *)
#define LOCAL_DEVICE_FILE_NAME "/dev/rpidatv-mb"
#define VCIO_DEVICE_FILE_NAME "/dev/vcio"
#define PAGE_SIZE (4*1024)
int mbox_open();
void mbox_close(int file_desc);
unsigned get_version(int file_desc);
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags);
unsigned mem_free(int file_desc, unsigned handle);
unsigned mem_lock(int file_desc, unsigned handle);
unsigned mem_unlock(int file_desc, unsigned handle);
void *mapmem(unsigned base, unsigned size);
void *unmapmem(void *addr, unsigned size);
unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5);
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout);
unsigned qpu_enable(int file_desc, unsigned enable);
#endif

View File

@@ -1,101 +0,0 @@
// Inspired by https://github.com/SaucySoliton/PiFmRds/blob/master/src/pi_fm_rds.c
#include "stdio.h"
#include "ngfmdmasync.h"
ngfmdmasync::ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,2,1)
{
tunefreq=TuneFrequency;
clkgpio::SetAdvancedPllMode(true);
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
clkgpio::SetFrequency(0);
clkgpio::enableclk(4); // GPIO 4 CLK by default
syncwithpwm=false;
if(syncwithpwm)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SampleRate);
}
else
{
pcmgpio::SetPllNumber(clk_plld,1);
pcmgpio::SetFrequency(SampleRate);
}
SetDmaAlgo();
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
}
ngfmdmasync::~ngfmdmasync()
{
clkgpio::disableclk(4);
}
void ngfmdmasync::SetPhase(bool inversed)
{
clkgpio::SetPhase(inversed);
}
void ngfmdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
// Write a frequency sample
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
// Delay
if(syncwithpwm)
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
else
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
if(syncwithpwm)
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
else
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void ngfmdmasync::SetFrequencySample(uint32_t Index,int Frequency)
{
Index=Index%buffersize;
sampletab[Index]=(0x5A<<24)|GetMasterFrac(Frequency);
//fprintf(stderr,"Frac=%d\n",GetMasterFrac(Frequency));
PushSample(Index);
}

View File

@@ -1,22 +0,0 @@
#ifndef DEF_NGFMDMASYNC
#define DEF_NGFMDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class ngfmdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
{
protected:
uint64_t tunefreq;
bool syncwithpwm;
public:
ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
~ngfmdmasync();
void SetDmaAlgo();
void SetPhase(bool inversed);
void SetFrequencySample(uint32_t Index,int Frequency);
};
#endif

View File

@@ -1,117 +0,0 @@
#include "stdio.h"
#include "phasedmasync.h"
#include <unistd.h>
phasedmasync::phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,2,1) // Number of phase between 2 and 16
{
SetMode(pwm1pinrepeat);
pwmgpio::SetPllNumber(clk_plla,0);
tunefreq=TuneFrequency*NumberOfPhase;
if((NumberOfPhase==2)||(NumberOfPhase==4)||(NumberOfPhase==8)||(NumberOfPhase==16)||(NumberOfPhase==32))
NumbPhase=NumberOfPhase;
else
fprintf(stderr,"PWM critical error: %d is not a legal number of phase\n",NumberOfPhase);
clkgpio::SetAdvancedPllMode(true);
clkgpio::ComputeBestLO(tunefreq,0); // compute PWM divider according to MasterPLL clkgpio::PllFixDivider
double FloatMult=((double)(tunefreq)*clkgpio::PllFixDivider)/(double)(XOSC_FREQUENCY);
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
freqctl&=0xFFFFF; // Fractionnal is 20bits
uint32_t FracMultiply=freqctl&0xFFFFF;
clkgpio::SetMasterMultFrac(IntMultiply,FracMultiply);
fprintf(stderr,"PWM Mult %d Frac %d Div %d\n",IntMultiply,FracMultiply,clkgpio::PllFixDivider);
pwmgpio::clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((clkgpio::PllFixDivider)<<12); // PWM clock input divider
usleep(100);
pwmgpio::clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (pwmgpio::Mash << 9) | pwmgpio::pllnumber|(1 << 4) ; //4 is START CLK
usleep(100);
pwmgpio::SetPrediv(32); //SetMode should be called before
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
pcmgpio::SetPllNumber(clk_plld,1);// Clk for Samplerate by PCM
pcmgpio::SetFrequency(SampleRate);
SetDmaAlgo();
uint32_t ZeroPhase=0;
switch(NumbPhase)
{
case 2:ZeroPhase=0xAAAAAAAA;break;//1,0,1,0 1,0,1,0
case 4:ZeroPhase=0xCCCCCCCC;break;//1,1,0,0 //4
case 8:ZeroPhase=0xF0F0F0F0;break;//1,1,1,1,0,0,0,0 //8
case 16:ZeroPhase=0xFF00FF00;break;//1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 //16
case 32:ZeroPhase=0xFFFF0000;break;//1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //32
default:fprintf(stderr,"Zero phase not initialized\n");break;
}
for(int i=0;i<NumbPhase;i++)
{
TabPhase[i]=ZeroPhase;
fprintf(stderr,"Phase[%d]=%x\n",i,TabPhase[i]);
ZeroPhase=(ZeroPhase<<1)|(ZeroPhase>>31);
}
}
phasedmasync::~phasedmasync()
{
disablepwm(12);
}
void phasedmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void phasedmasync::SetPhase(uint32_t Index,int Phase)
{
Index=Index%buffersize;
Phase=Phase%NumbPhase;
sampletab[Index]=TabPhase[Phase];
PushSample(Index);
}

View File

@@ -1,22 +0,0 @@
#ifndef DEF_PHASEDMASYNC
#define DEF_PHASEDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class phasedmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio,public generalgpio
{
protected:
uint64_t tunefreq;
int NumbPhase=2;
uint32_t TabPhase[32];//32 is Max Phase
public:
phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize);
~phasedmasync();
void SetDmaAlgo();
void SetPhase(uint32_t Index,int Phase);
};
#endif

View File

@@ -1,763 +0,0 @@
//-------------------------------------------------------------------------
//
// The MIT License (MIT)
//
// Copyright (c) 2015 Andrew Duncan
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//-------------------------------------------------------------------------
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "raspberry_pi_revision.h"
//-------------------------------------------------------------------------
//
// The file /proc/cpuinfo contains a line such as:-
//
// Revision : 0003
//
// that holds the revision number of the Raspberry Pi.
// Known revisions (prior to the Raspberry Pi 2) are:
//
// +----------+---------+---------+--------+-------------+
// | Revision | Model | PCB Rev | Memory | Manufacture |
// +----------+---------+---------+--------+-------------+
// | 0000 | | | | |
// | 0001 | | | | |
// | 0002 | B | 1 | 256 MB | |
// | 0003 | B | 1 | 256 MB | |
// | 0004 | B | 2 | 256 MB | Sony |
// | 0005 | B | 2 | 256 MB | Qisda |
// | 0006 | B | 2 | 256 MB | Egoman |
// | 0007 | A | 2 | 256 MB | Egoman |
// | 0008 | A | 2 | 256 MB | Sony |
// | 0009 | A | 2 | 256 MB | Qisda |
// | 000a | | | | |
// | 000b | | | | |
// | 000c | | | | |
// | 000d | B | 2 | 512 MB | Egoman |
// | 000e | B | 2 | 512 MB | Sony |
// | 000f | B | 2 | 512 MB | Qisda |
// | 0010 | B+ | 1 | 512 MB | Sony |
// | 0011 | compute | 1 | 512 MB | Sony |
// | 0012 | A+ | 1 | 256 MB | Sony |
// | 0013 | B+ | 1 | 512 MB | Embest |
// | 0014 | compute | 1 | 512 MB | Sony |
// | 0015 | A+ | 1 | 256 MB | Sony |
// +----------+---------+---------+--------+-------------+
//
// If the Raspberry Pi has been over-volted (voiding the warranty) the
// revision number will have 100 at the front. e.g. 1000002.
//
//-------------------------------------------------------------------------
//
// With the release of the Raspberry Pi 2, there is a new encoding of the
// Revision field in /proc/cpuinfo. The bit fields are as follows
//
// +----+----+----+----+----+----+----+----+
// |FEDC|BA98|7654|3210|FEDC|BA98|7654|3210|
// +----+----+----+----+----+----+----+----+
// | | | | | | | |AAAA|
// | | | | | |BBBB|BBBB| |
// | | | | |CCCC| | | |
// | | | |DDDD| | | | |
// | | | EEE| | | | | |
// | | |F | | | | | |
// | | G| | | | | | |
// | | H | | | | | | |
// +----+----+----+----+----+----+----+----+
// |1098|7654|3210|9876|5432|1098|7654|3210|
// +----+----+----+----+----+----+----+----+
//
// +---+-------+--------------+--------------------------------------------+
// | # | bits | contains | values |
// +---+-------+--------------+--------------------------------------------+
// | A | 00-03 | PCB Revision | (the pcb revision number) |
// | B | 04-11 | Model name | A, B, A+, B+, B Pi2, Alpha, Compute Module |
// | | | | unknown, unknown, Zero |
// | C | 12-15 | Processor | BCM2835, BCM2836, BCM2837 |
// | D | 16-19 | Manufacturer | Sony, Egoman, Embest, unknown, Embest |
// | E | 20-22 | Memory size | 256 MB, 512 MB, 1024 MB |
// | F | 23-23 | encoded flag | (if set, revision is a bit field) |
// | G | 24-24 | waranty bit | (if set, warranty void - Pre Pi2) |
// | H | 25-25 | waranty bit | (if set, warranty void - Post Pi2) |
// +---+-------+--------------+--------------------------------------------+
//
// Also, due to some early issues the warranty bit has been move from bit
// 24 to bit 25 of the revision number (i.e. 0x2000000).
//
// e.g.
//
// Revision : A01041
//
// A - PCB Revision - 1 (first revision)
// B - Model Name - 4 (Model B Pi 2)
// C - Processor - 1 (BCM2836)
// D - Manufacturer - 0 (Sony)
// E - Memory - 2 (1024 MB)
// F - Endcoded flag - 1 (encoded cpu info)
//
// Revision : A21041
//
// A - PCB Revision - 1 (first revision)
// B - Model Name - 4 (Model B Pi 2)
// C - Processor - 1 (BCM2836)
// D - Manufacturer - 2 (Embest)
// E - Memory - 2 (1024 MB)
// F - Endcoded flag - 1 (encoded cpu info)
//
// Revision : 900092
//
// A - PCB Revision - 2 (second revision)
// B - Model Name - 9 (Model Zero)
// C - Processor - 0 (BCM2835)
// D - Manufacturer - 0 (Sony)
// E - Memory - 1 (512 MB)
// F - Endcoded flag - 1 (encoded cpu info)
//
// Revision : A02082
//
// A - PCB Revision - 2 (first revision)
// B - Model Name - 8 (Model B Pi 3)
// C - Processor - 2 (BCM2837)
// D - Manufacturer - 0 (Sony)
// E - Memory - 2 (1024 MB)
// F - Endcoded flag - 1 (encoded cpu info)
//
//-------------------------------------------------------------------------
static RASPBERRY_PI_MEMORY_T revisionToMemory[] =
{
RPI_MEMORY_UNKNOWN, // 0
RPI_MEMORY_UNKNOWN, // 1
RPI_256MB, // 2
RPI_256MB, // 3
RPI_256MB, // 4
RPI_256MB, // 5
RPI_256MB, // 6
RPI_256MB, // 7
RPI_256MB, // 8
RPI_256MB, // 9
RPI_MEMORY_UNKNOWN, // A
RPI_MEMORY_UNKNOWN, // B
RPI_MEMORY_UNKNOWN, // C
RPI_512MB, // D
RPI_512MB, // E
RPI_512MB, // F
RPI_512MB, // 10
RPI_512MB, // 11
RPI_256MB, // 12
RPI_512MB, // 13
RPI_512MB, // 14
RPI_256MB // 15
};
static RASPBERRY_PI_MEMORY_T bitFieldToMemory[] =
{
RPI_256MB,
RPI_512MB,
RPI_1024MB
};
//-------------------------------------------------------------------------
static RASPBERRY_PI_PROCESSOR_T bitFieldToProcessor[] =
{
RPI_BROADCOM_2835,
RPI_BROADCOM_2836,
RPI_BROADCOM_2837
};
//-------------------------------------------------------------------------
static RASPBERRY_PI_I2C_DEVICE_T revisionToI2CDevice[] =
{
RPI_I2C_DEVICE_UNKNOWN, // 0
RPI_I2C_DEVICE_UNKNOWN, // 1
RPI_I2C_0, // 2
RPI_I2C_0, // 3
RPI_I2C_1, // 4
RPI_I2C_1, // 5
RPI_I2C_1, // 6
RPI_I2C_1, // 7
RPI_I2C_1, // 8
RPI_I2C_1, // 9
RPI_I2C_DEVICE_UNKNOWN, // A
RPI_I2C_DEVICE_UNKNOWN, // B
RPI_I2C_DEVICE_UNKNOWN, // C
RPI_I2C_1, // D
RPI_I2C_1, // E
RPI_I2C_1, // F
RPI_I2C_1, // 10
RPI_I2C_1, // 11
RPI_I2C_1, // 12
RPI_I2C_1, // 13
RPI_I2C_1, // 14
RPI_I2C_1 // 15
};
//-------------------------------------------------------------------------
static RASPBERRY_PI_MODEL_T bitFieldToModel[] =
{
RPI_MODEL_A,
RPI_MODEL_B,
RPI_MODEL_A_PLUS,
RPI_MODEL_B_PLUS,
RPI_MODEL_B_PI_2,
RPI_MODEL_ALPHA,
RPI_COMPUTE_MODULE,
RPI_MODEL_UNKNOWN,
RPI_MODEL_B_PI_3,
RPI_MODEL_ZERO
};
static RASPBERRY_PI_MODEL_T revisionToModel[] =
{
RPI_MODEL_UNKNOWN, // 0
RPI_MODEL_UNKNOWN, // 1
RPI_MODEL_B, // 2
RPI_MODEL_B, // 3
RPI_MODEL_B, // 4
RPI_MODEL_B, // 5
RPI_MODEL_B, // 6
RPI_MODEL_A, // 7
RPI_MODEL_A, // 8
RPI_MODEL_A, // 9
RPI_MODEL_UNKNOWN, // A
RPI_MODEL_UNKNOWN, // B
RPI_MODEL_UNKNOWN, // C
RPI_MODEL_B, // D
RPI_MODEL_B, // E
RPI_MODEL_B, // F
RPI_MODEL_B_PLUS, // 10
RPI_COMPUTE_MODULE, // 11
RPI_MODEL_A_PLUS, // 12
RPI_MODEL_B_PLUS, // 13
RPI_COMPUTE_MODULE, // 14
RPI_MODEL_A_PLUS // 15
};
//-------------------------------------------------------------------------
static RASPBERRY_PI_MANUFACTURER_T bitFieldToManufacturer[] =
{
RPI_MANUFACTURER_SONY,
RPI_MANUFACTURER_EGOMAN,
RPI_MANUFACTURER_EMBEST,
RPI_MANUFACTURER_UNKNOWN,
RPI_MANUFACTURER_EMBEST
};
static RASPBERRY_PI_MANUFACTURER_T revisionToManufacturer[] =
{
RPI_MANUFACTURER_UNKNOWN, // 0
RPI_MANUFACTURER_UNKNOWN, // 1
RPI_MANUFACTURER_UNKNOWN, // 2
RPI_MANUFACTURER_UNKNOWN, // 3
RPI_MANUFACTURER_SONY, // 4
RPI_MANUFACTURER_QISDA, // 5
RPI_MANUFACTURER_EGOMAN, // 6
RPI_MANUFACTURER_EGOMAN, // 7
RPI_MANUFACTURER_SONY, // 8
RPI_MANUFACTURER_QISDA, // 9
RPI_MANUFACTURER_UNKNOWN, // A
RPI_MANUFACTURER_UNKNOWN, // B
RPI_MANUFACTURER_UNKNOWN, // C
RPI_MANUFACTURER_EGOMAN, // D
RPI_MANUFACTURER_SONY, // E
RPI_MANUFACTURER_QISDA, // F
RPI_MANUFACTURER_SONY, // 10
RPI_MANUFACTURER_SONY, // 11
RPI_MANUFACTURER_SONY, // 12
RPI_MANUFACTURER_EMBEST, // 13
RPI_MANUFACTURER_SONY, // 14
RPI_MANUFACTURER_SONY // 15
};
//-------------------------------------------------------------------------
static int revisionToPcbRevision[] =
{
0, // 0
0, // 1
1, // 2
1, // 3
2, // 4
2, // 5
2, // 6
2, // 7
2, // 8
2, // 9
0, // A
0, // B
0, // C
2, // D
2, // E
2, // F
1, // 10
1, // 11
1, // 12
1, // 13
1, // 14
1 // 15
};
//-------------------------------------------------------------------------
//
// Remove leading and trailing whitespace from a string.
static char *
trimWhiteSpace(
char *string)
{
if (string == NULL)
{
return NULL;
}
while (isspace(*string))
{
string++;
}
if (*string == '\0')
{
return string;
}
char *end = string;
while (*end)
{
++end;
}
--end;
while ((end > string) && isspace(*end))
{
end--;
}
*(end + 1) = 0;
return string;
}
//-------------------------------------------------------------------------
int
getRaspberryPiRevision()
{
int raspberryPiRevision = 0;
FILE *fp = fopen("/proc/cpuinfo", "r");
if (fp == NULL)
{
perror("/proc/cpuinfo");
return raspberryPiRevision;
}
char entry[80];
while (fgets(entry, sizeof(entry), fp) != NULL)
{
char* saveptr = NULL;
char *key = trimWhiteSpace(strtok_r(entry, ":", &saveptr));
char *value = trimWhiteSpace(strtok_r(NULL, ":", &saveptr));
if (strcasecmp("Revision", key) == 0)
{
raspberryPiRevision = strtol(value, NULL, 16);
}
}
fclose(fp);
return raspberryPiRevision;
}
//-------------------------------------------------------------------------
int
getRaspberryPiInformation(
RASPBERRY_PI_INFO_T *info)
{
int revision = getRaspberryPiRevision();
return getRaspberryPiInformationForRevision(revision, info);
}
//-------------------------------------------------------------------------
int
getRaspberryPiInformationForRevision(
int revision,
RASPBERRY_PI_INFO_T *info)
{
int result = 0;
if (info != NULL)
{
info->memory = RPI_MEMORY_UNKNOWN;
info->processor = RPI_PROCESSOR_UNKNOWN;
info->i2cDevice = RPI_I2C_DEVICE_UNKNOWN;
info->model = RPI_MODEL_UNKNOWN;
info->manufacturer = RPI_MANUFACTURER_UNKNOWN;
info->pcbRevision = 0;
info->warrantyBit = 0;
info->revisionNumber = revision;
info->peripheralBase = RPI_PERIPHERAL_BASE_UNKNOWN;
if (revision != 0)
{
size_t maxOriginalRevision = (sizeof(revisionToModel) /
sizeof(revisionToModel[0])) - 1;
// remove warranty bit
revision &= ~0x3000000;
if (revision & 0x800000)
{
// Raspberry Pi2 style revision encoding
result = 2;
if (info->revisionNumber & 0x2000000)
{
info->warrantyBit = 1;
}
int memoryIndex = (revision & 0x700000) >> 20;
size_t knownMemoryValues = sizeof(bitFieldToMemory)
/ sizeof(bitFieldToMemory[0]);
if (memoryIndex < knownMemoryValues)
{
info->memory = bitFieldToMemory[memoryIndex];
}
else
{
info->memory = RPI_MEMORY_UNKNOWN;
}
int processorIndex = (revision & 0xF000) >> 12;
size_t knownProcessorValues = sizeof(bitFieldToProcessor)
/ sizeof(bitFieldToProcessor[0]);
if (processorIndex < knownProcessorValues)
{
info->processor = bitFieldToProcessor[processorIndex];
}
else
{
info->processor = RPI_PROCESSOR_UNKNOWN;
}
// If some future firmware changes the Rev number of
// older Raspberry Pis, then need to work out the i2c
// device.
info->i2cDevice = RPI_I2C_1;
int modelIndex = (revision & 0xFF0) >> 4;
size_t knownModelValues = sizeof(bitFieldToModel)
/ sizeof(bitFieldToModel[0]);
if (modelIndex < knownModelValues)
{
info->model = bitFieldToModel[modelIndex];
}
else
{
info->model = RPI_MODEL_UNKNOWN;
}
int madeByIndex = (revision & 0xF0000) >> 16;
size_t knownManufacturerValues = sizeof(bitFieldToManufacturer)
/ sizeof(bitFieldToManufacturer[0]);
if (madeByIndex < knownManufacturerValues)
{
info->manufacturer = bitFieldToManufacturer[madeByIndex];
}
else
{
info->manufacturer = RPI_MANUFACTURER_UNKNOWN;
}
info->pcbRevision = revision & 0xF;
}
else if (revision <= maxOriginalRevision)
{
// Original revision encoding
result = 1;
if (info->revisionNumber & 0x1000000)
{
info->warrantyBit = 1;
}
info->memory = revisionToMemory[revision];
info->i2cDevice = revisionToI2CDevice[revision];
info->model = revisionToModel[revision];
info->manufacturer = revisionToManufacturer[revision];
info->pcbRevision = revisionToPcbRevision[revision];
if (info->model == RPI_MODEL_UNKNOWN)
{
info->processor = RPI_PROCESSOR_UNKNOWN;
}
else
{
info->processor = RPI_BROADCOM_2835;
}
}
}
switch (info->processor)
{
case RPI_PROCESSOR_UNKNOWN:
info->peripheralBase = RPI_PERIPHERAL_BASE_UNKNOWN;
break;
case RPI_BROADCOM_2835:
info->peripheralBase = RPI_BROADCOM_2835_PERIPHERAL_BASE;
break;
case RPI_BROADCOM_2836:
info->peripheralBase = RPI_BROADCOM_2836_PERIPHERAL_BASE;
break;
case RPI_BROADCOM_2837:
info->peripheralBase = RPI_BROADCOM_2837_PERIPHERAL_BASE;
break;
}
}
return result;
}
//-------------------------------------------------------------------------
const char *
raspberryPiMemoryToString(
RASPBERRY_PI_MEMORY_T memory)
{
const char *string = "unknown";
switch(memory)
{
case RPI_256MB:
string = "256 MB";
break;
case RPI_512MB:
string = "512 MB";
break;
case RPI_1024MB:
string = "1024 MB";
break;
default:
break;
}
return string;
}
//-------------------------------------------------------------------------
const char *
raspberryPiProcessorToString(
RASPBERRY_PI_PROCESSOR_T processor)
{
const char *string = "unknown";
switch(processor)
{
case RPI_BROADCOM_2835:
string = "Broadcom BCM2835";
break;
case RPI_BROADCOM_2836:
string = "Broadcom BCM2836";
break;
case RPI_BROADCOM_2837:
string = "Broadcom BCM2837";
break;
default:
break;
}
return string;
}
//-------------------------------------------------------------------------
const char *
raspberryPiI2CDeviceToString(
RASPBERRY_PI_I2C_DEVICE_T i2cDevice)
{
const char *string = "unknown";
switch(i2cDevice)
{
case RPI_I2C_0:
string = "/dev/i2c-0";
break;
case RPI_I2C_1:
string = "/dev/i2c-1";
break;
default:
break;
}
return string;
}
//-------------------------------------------------------------------------
const char *
raspberryPiModelToString(
RASPBERRY_PI_MODEL_T model)
{
const char *string = "unknown";
switch(model)
{
case RPI_MODEL_A:
string = "Model A";
break;
case RPI_MODEL_B:
string = "Model B";
break;
case RPI_MODEL_A_PLUS:
string = "Model A+";
break;
case RPI_MODEL_B_PLUS:
string = "Model B+";
break;
case RPI_MODEL_B_PI_2:
string = "Model B Pi 2";
break;
case RPI_MODEL_ALPHA:
string = "Alpha";
break;
case RPI_COMPUTE_MODULE:
string = "Compute Module";
break;
case RPI_MODEL_ZERO:
string = "Model Zero";
break;
case RPI_MODEL_B_PI_3:
string = "Model B Pi 3";
break;
default:
break;
}
return string;
}
//-------------------------------------------------------------------------
const char *
raspberryPiManufacturerToString(
RASPBERRY_PI_MANUFACTURER_T manufacturer)
{
const char *string = "unknown";
switch(manufacturer)
{
case RPI_MANUFACTURER_SONY:
string = "Sony";
break;
case RPI_MANUFACTURER_EGOMAN:
string = "Egoman";
break;
case RPI_MANUFACTURER_QISDA:
string = "Qisda";
break;
case RPI_MANUFACTURER_EMBEST:
string = "Embest";
break;
default:
break;
}
return string;
}

View File

@@ -1,163 +0,0 @@
//-------------------------------------------------------------------------
//
// The MIT License (MIT)
//
// Copyright (c) 2015 Andrew Duncan
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//-------------------------------------------------------------------------
#ifndef RASPBERRY_PI_INFO_H
#define RASPBERRY_PI_INFO_H
//-------------------------------------------------------------------------
#include <stdint.h>
//-------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
//-------------------------------------------------------------------------
#define RPI_PERIPHERAL_BASE_UNKNOWN 0
#define RPI_BROADCOM_2835_PERIPHERAL_BASE 0x20000000
#define RPI_BROADCOM_2836_PERIPHERAL_BASE 0x3F000000
#define RPI_BROADCOM_2837_PERIPHERAL_BASE 0x3F000000
typedef enum
{
RPI_MEMORY_UNKNOWN = -1,
RPI_256MB = 256,
RPI_512MB = 512,
RPI_1024MB = 1024,
}
RASPBERRY_PI_MEMORY_T;
typedef enum
{
RPI_PROCESSOR_UNKNOWN = -1,
RPI_BROADCOM_2835 = 2835,
RPI_BROADCOM_2836 = 2836,
RPI_BROADCOM_2837 = 2837
}
RASPBERRY_PI_PROCESSOR_T;
typedef enum
{
RPI_I2C_DEVICE_UNKNOWN = -1,
RPI_I2C_0 = 0,
RPI_I2C_1 = 1
}
RASPBERRY_PI_I2C_DEVICE_T;
typedef enum
{
RPI_MODEL_UNKNOWN = -1,
RPI_MODEL_A,
RPI_MODEL_B,
RPI_MODEL_A_PLUS,
RPI_MODEL_B_PLUS,
RPI_MODEL_B_PI_2,
RPI_MODEL_ALPHA,
RPI_COMPUTE_MODULE,
RPI_MODEL_ZERO,
RPI_MODEL_B_PI_3
}
RASPBERRY_PI_MODEL_T;
typedef enum
{
RPI_MANUFACTURER_UNKNOWN = -1,
RPI_MANUFACTURER_SONY,
RPI_MANUFACTURER_EGOMAN,
RPI_MANUFACTURER_QISDA,
RPI_MANUFACTURER_EMBEST,
}
RASPBERRY_PI_MANUFACTURER_T;
//-------------------------------------------------------------------------
typedef struct
{
RASPBERRY_PI_MEMORY_T memory;
RASPBERRY_PI_PROCESSOR_T processor;
RASPBERRY_PI_I2C_DEVICE_T i2cDevice;
RASPBERRY_PI_MODEL_T model;
RASPBERRY_PI_MANUFACTURER_T manufacturer;
int pcbRevision;
int warrantyBit;
int revisionNumber;
uint32_t peripheralBase;
}
RASPBERRY_PI_INFO_T;
//-------------------------------------------------------------------------
// getRaspberryPiInformation()
//
// return - 0 - failed to get revision from /proc/cpuinfo
// 1 - found classic revision number
// 2 - found Pi 2 style revision number
int
getRaspberryPiInformation(
RASPBERRY_PI_INFO_T *info);
int
getRaspberryPiInformationForRevision(
int revision,
RASPBERRY_PI_INFO_T *info);
int
getRaspberryPiRevision(void);
const char *
raspberryPiMemoryToString(
RASPBERRY_PI_MEMORY_T memory);
const char *
raspberryPiProcessorToString(
RASPBERRY_PI_PROCESSOR_T processor);
const char *
raspberryPiI2CDeviceToString(
RASPBERRY_PI_I2C_DEVICE_T i2cDevice);
const char *
raspberryPiModelToString(
RASPBERRY_PI_MODEL_T model);
const char *
raspberryPiManufacturerToString(
RASPBERRY_PI_MANUFACTURER_T manufacturer);
//-------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif
//-------------------------------------------------------------------------
#endif

View File

@@ -1,78 +0,0 @@
#include "stdio.h"
#include "serialdmasync.h"
serialdmasync::serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput):bufferdma(Channel,FifoSize,1,1)
{
if(dualoutput) //Fixme if 2pin we want maybe 2*SRATE as it is distributed over 2 pin
{
pwmgpio::SetMode(pwm2pin);
SampleRate*=2;
}
else
{
pwmgpio::SetMode(pwm1pin);
}
if(SampleRate>250000)
{
pwmgpio::SetPllNumber(clk_plld,1);
pwmgpio::SetFrequency(SampleRate);
}
else
{
pwmgpio::SetPllNumber(clk_osc,1);
pwmgpio::SetFrequency(SampleRate);
}
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
enablepwm(13,0); // By default PWM on GPIO 13/pin 33
SetDmaAlgo();
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
}
serialdmasync::~serialdmasync()
{
}
void serialdmasync::SetDmaAlgo()
{
dma_cb_t *cbp = cbarray;
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
{
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
cbp->length = 4;
cbp->stride = 0;
cbp->next = mem_virt_to_phys(cbp + 1);
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
cbp++;
}
cbp--;
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
}
void serialdmasync::SetSample(uint32_t Index,int Sample)
{
Index=Index%buffersize;
sampletab[Index]=Sample;
PushSample(Index);
}

View File

@@ -1,20 +0,0 @@
#ifndef DEF_SERIALDMASYNC
#define DEF_SERIALDMASYNC
#include "stdint.h"
#include "dma.h"
#include "gpio.h"
class serialdmasync:public bufferdma,public clkgpio,public pwmgpio
{
protected:
uint64_t tunefreq;
bool syncwithpwm;
public:
serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput);
~serialdmasync();
void SetDmaAlgo();
void SetSample(uint32_t Index,int Sample);
};
#endif

Binary file not shown.

View File

@@ -1,402 +0,0 @@
#include <unistd.h>
#include "librpitx.h"
#include <unistd.h>
#include "stdio.h"
#include <cstring>
#include <signal.h>
bool running=true;
void SimpleTest(uint64_t Freq)
{
generalgpio genpio;
fprintf(stderr,"GPIOPULL =%x\n",genpio.gpioreg[GPPUDCLK0]);
#define PULL_OFF 0
#define PULL_DOWN 1
#define PULL_UP 2
genpio.gpioreg[GPPUD]=PULL_DOWN;
usleep(100);
genpio.gpioreg[GPPUDCLK0]=(1<<4); //GPIO CLK is GPIO 4
usleep(100);
//genpio.gpioreg[GPPUDCLK0]=(0); //GPIO CLK is GPIO 4
clkgpio clk;
clk.print_clock_tree();
//clk.SetPllNumber(clk_plld,2);
clk.SetAdvancedPllMode(true);
clk.SetCenterFrequency(Freq,100000);
int Deviation=0;
clk.SetFrequency(000);
clk.enableclk(4);
while(running)
{
sleep(5);
//Deviation+=1;
clk.SetFrequency(Deviation);
}
/*for(int i=0;i<100000;i+=1)
{
clk.SetFrequency(i);
usleep(1000);
}*/
clk.disableclk(4);
}
void SimpleTestDMA(uint64_t Freq)
{
int SR=200000;
int FifoSize=4096;
//ngfmdmasync ngfmtest(1244200000,SR,14,FifoSize);
ngfmdmasync ngfmtest(Freq,SR,14,FifoSize);
for(int i=0;running;)
{
//usleep(10);
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
int Available=ngfmtest.GetBufferAvailable();
if(Available>FifoSize/2)
{
int Index=ngfmtest.GetUserMemIndex();
//printf("GetIndex=%d\n",Index);
for(int j=0;j<Available;j++)
{
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
ngfmtest.SetFrequencySample(Index+j,(i%SR));
i++;
}
}
}
fprintf(stderr,"End\n");
ngfmtest.stop();
}
using std::complex;
void SimpleTestLiquid()
{
int SR=200000;
int FifoSize=4096;
ngfmdmasync ngfmtest(144200000,SR,14,FifoSize);
dsp mydsp(SR);
nco_crcf q = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_phase(q, 0.0f);
nco_crcf_set_frequency(q, -0.2f);
//ngfmtest.print_clock_tree();
for(int i=0;(i<SR)&&running;)
{
//usleep(10);
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
int Available=ngfmtest.GetBufferAvailable();
if(Available>FifoSize/2)
{
int Index=ngfmtest.GetUserMemIndex();
//printf("GetIndex=%d\n",Index);
for(int j=0;j<Available;j++)
{
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
//ngfmtest.SetFrequencySample(Index+j,(i%SR));
nco_crcf_adjust_frequency(q,1e-5);
liquid_float_complex x;
nco_crcf_step(q);
nco_crcf_cexpf(q, &x);
mydsp.pushsample(x);
if(mydsp.frequency>SR) mydsp.frequency=SR;
if(mydsp.frequency<-SR) mydsp.frequency=-SR;
ngfmtest.SetFrequencySample(Index+j,mydsp.frequency);
//fprintf(stderr,"freq=%f Amp=%f\n",mydsp.frequency,mydsp.amplitude);
//fprintf(stderr,"freq=%f\n",nco_crcf_get_frequency(q)*SR);
i++;
}
}
}
fprintf(stderr,"End\n");
ngfmtest.stop();
}
void SimpleTestFileIQ(uint64_t Freq)
{
FILE *iqfile=NULL;
iqfile=fopen("../ssbtest.iq","rb");
if (iqfile==NULL) printf("input file issue\n");
bool stereo=true;
int SR=48000;
int FifoSize=512;
//iqdmasync iqtest(1245000000,SR,14,FifoSize);
//iqdmasync iqtest(50100000,SR,14,FifoSize);
iqdmasync iqtest(Freq,SR,14,FifoSize);
//iqdmasync iqtest(14100000,SR,14,FifoSize);
short IQBuffer[128*2];
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(100);
int Available=iqtest.GetBufferAvailable();
if(Available>256)
{
int Index=iqtest.GetUserMemIndex();
int nbread=fread(IQBuffer,sizeof(short),128*2,iqfile);
if(nbread>0)
{
//printf("NbRead=%d\n",nbread);
for(int i=0;i<nbread/2;i++)
{
liquid_float_complex x=complex<float>(IQBuffer[i*2]/32768.0,IQBuffer[i*2+1]/32768.0);
iqtest.SetIQSample(Index+i,x);
}
}
else
{
printf("End of file\n");
fseek ( iqfile , 0 , SEEK_SET );
//break;
}
}
}
iqtest.stop();
}
void SimpleTestbpsk(uint64_t Freq)
{
clkgpio clk;
clk.print_clock_tree();
int SR=100000;
int FifoSize=1024;
int NumberofPhase=2;
phasedmasync biphase(Freq,SR,NumberofPhase,14,FifoSize);
int lastphase=0;
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(10);
int Available=biphase.GetBufferAvailable();
if(Available>256)
{
int Index=biphase.GetUserMemIndex();
for(int i=0;i<Available;i++)
{
int phase=(rand()%NumberofPhase);
biphase.SetPhase(Index+i,phase);
}
/*
for(int i=0;i<Available/2;i++)
{
int phase=2*(rand()%NumberofPhase/2);
biphase.SetPhase(Index+i*2,(phase+lastphase)/2);
biphase.SetPhase(Index+i*2+1,phase);
lastphase=phase;
}*/
/*for(int i=0;i<Available;i++)
{
lastphase=(lastphase+1)%NumberofPhase;
biphase.SetPhase(Index+i,lastphase);
}*/
}
}
biphase.stop();
}
void SimpleTestSerial()
{
bool stereo=true;
int SR=10000;
int FifoSize=1024;
bool dualoutput=true;
serialdmasync testserial(SR,14,FifoSize,dualoutput);
while(running)
{
usleep(10);
int Available=testserial.GetBufferAvailable();
if(Available>256)
{
int Index=testserial.GetUserMemIndex();
for(int i=0;i<Available;i++)
{
testserial.SetSample(Index+i,i);
}
}
}
testserial.stop();
}
void SimpleTestAm(uint64_t Freq)
{
FILE *audiofile=NULL;
audiofile=fopen("../ssbaudio48.wav","rb");
if (audiofile==NULL) printf("input file issue\n");
bool Stereo=true;
int SR=48000;
int FifoSize=512;
amdmasync amtest(Freq,SR,14,FifoSize);
short AudioBuffer[128*2];
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(100);
int Available=amtest.GetBufferAvailable();
if(Available>256)
{
int Index=amtest.GetUserMemIndex();
int nbread=fread(AudioBuffer,sizeof(short),128*2,audiofile);
if(nbread>0)
{
for(int i=0;i<nbread/2;i++)
{
if(!Stereo)
{
float x=((AudioBuffer[i*2]/32768.0)+(AudioBuffer[i*2+1]/32768.0))/4.0;
amtest.SetAmSample(Index+i,x);
}
else
{
float x=((AudioBuffer[i]/32768.0)/2.0)*8.0;
amtest.SetAmSample(Index+i,x);
}
}
}
else
{
printf("End of file\n");
fseek ( audiofile , 0 , SEEK_SET );
//break;
}
}
}
amtest.stop();
}
void SimpleTestOOK(uint64_t Freq)
{
int SR=1000;
int FifoSize=512;
amdmasync amtest(Freq,SR,14,FifoSize);
int count=0;
int Every=SR/100;
float x=0.0;
while(running)
{
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
usleep(100);
int Available=amtest.GetBufferAvailable();
if(Available>256)
{
int Index=amtest.GetUserMemIndex();
for(int i=0;i<Available;i++)
{
//if((count/Every)%4>2) x=0; else x=1;
//x+=(1.0/(float)SR*10.0);
x+=0.0001;
if(x>1.0) x=0;
amtest.SetAmSample(Index+i,x);
count++;
}
}
}
amtest.stop();
}
void SimpleTestBurstFsk(uint64_t Freq)
{
//int SR=40625;
int SR=10000;
int Deviation=26370;
int FiFoSize=4000;
fskburst fsktest(Freq,SR,Deviation,14,FiFoSize);
unsigned char TabSymbol[FiFoSize];
int BurstSize=100;
while(running)
{
int i;
for(i=0;i<FiFoSize;i++)
{
TabSymbol[i]=(i/10)%2;
}
fsktest.SetSymbols(TabSymbol,FiFoSize);
sleep(1);
fsktest.SetSymbols(TabSymbol,FiFoSize/2);
sleep(1);
}
fsktest.stop();
}
static void
terminate(int num)
{
running=false;
fprintf(stderr,"Caught signal - Terminating\n");
}
int main(int argc, char* argv[])
{
uint64_t Freq=144200000;
if(argc>1)
Freq=atol(argv[1]);
for (int i = 0; i < 64; i++) {
struct sigaction sa;
std::memset(&sa, 0, sizeof(sa));
sa.sa_handler = terminate;
sigaction(i, &sa, NULL);
}
//SimpleTest(Freq);
//SimpleTestbpsk(Freq);
//SimpleTestFileIQ(Freq);
//SimpleTestDMA(Freq);
//SimpleTestAm(Freq);
//SimpleTestOOK(Freq);
SimpleTestBurstFsk(Freq);
}

View File

@@ -1,13 +0,0 @@
#Makefile
CC=gcc -pipe
CFLAGS=-Wall -g
OBJS=ssb_gen.o test_ssb.o
HEADERS=ssb_gen.h
LIBS=-lsndfile
%.o:%.c $(HEADERS) Makefile
$(CC) $(CFLAGS) -c $< -o $@
testssb:$(OBJS) $(HEADERS) test_ssb.o
$(CC) -o testssb $(OBJS) $(LIBS)

View File

@@ -1,589 +0,0 @@
//==========================================================================================
// + + + This Software is released under the "Simplified BSD License" + + +
// Copyright 2014 F4GKR Sylvain AZARIAN . All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Sylvain AZARIAN F4GKR ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Sylvain AZARIAN OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Sylvain AZARIAN F4GKR.
//==========================================================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "ssb_gen.h"
struct FIR {
float *coeffs;
int filterLength;
float *delay_line;
};
typedef struct _cpx {
float re;
float im;
} TYPECPX;
struct cFIR {
float *coeffs;
int filterLength;
TYPECPX *delay_line;
float rms;
};
#define ALPHA_DC_REMOVE (0.999)
struct FIR* audio_fir;
struct FIR* hilbert;
struct FIR* delay;
struct cFIR* interpolateIQ;
// Create a FIR struct, used to store a copy of coeffs and delay line
// in : coeffs_len = coeff tab length
// double *coeff_tab = pointer to the coefficients
// out: a struct FIR
struct FIR* init_fir( int coeffs_len, float *coeff_tab )
{
struct FIR *result;
int i;
// alloc and init buffers
result = (struct FIR *)malloc( sizeof( struct FIR ));
result->filterLength = coeffs_len;
result->coeffs = (float*)malloc( coeffs_len * sizeof( float));
result->delay_line = (float*)malloc( coeffs_len * sizeof( float));
// copy coeffs to struct
for( i=0 ; i < coeffs_len ; i++ ) {
result->delay_line[i] = 0.0;
result->coeffs[i] = coeff_tab[i];
}
return( result );
}
// init a complex in -> complex out fir with real coeffs
struct cFIR* init_cfir( int coeffs_len, float *coeff_tab )
{
struct cFIR *result;
int i;
// alloc and init buffers
result = (struct cFIR *)malloc( sizeof( struct cFIR ));
result->filterLength = coeffs_len ;
result->coeffs = (float*)malloc( coeffs_len * sizeof( float));
result->delay_line = (TYPECPX*)malloc( coeffs_len * sizeof( TYPECPX));
// copy coeffs to struct
for( i=0 ; i < coeffs_len ; i++ ) {
result->delay_line[i].re = 0.0;
result->delay_line[i].im = 0.0;
result->coeffs[i] = coeff_tab[i];
}
return( result );
}
float fir_filt( struct FIR* f, float in )
{
int i;
float acc;
float *pt_coeffs;
float *pt_sample;
int L;
// shift input left for one sample
L = f->filterLength;
for( i=0 ; i < L - 1 ; i++ ) {
f->delay_line[i] = f->delay_line[i+1];
}
// add new sample to the end of delay line
f->delay_line[ L - 1 ] = in;
acc = 0 ;
pt_sample = f->delay_line;
pt_coeffs = f->coeffs;
// do the compute loop
for( i=0 ; i < L ; i++ ) {
acc += (*pt_sample) * (*pt_coeffs );
pt_sample++;
pt_coeffs++;
}
return( acc );
}
// same but we filter a complex number at input, out is a complex
TYPECPX cfir_filt( struct cFIR* f, TYPECPX in )
{
int i;
TYPECPX acc;
float *pt_coeffs, rms;
TYPECPX *pt_sample;
int L;
// shift input left for one sample
L = f->filterLength;
for( i=0 ; i < L - 1 ; i++ ){
f->delay_line[i] = f->delay_line[i+1];
}
// add new sample to the end of delay line
f->delay_line[ L - 1 ] = in;
acc.re = acc.im = 0;
pt_sample = f->delay_line;
pt_coeffs = f->coeffs;
// do the compute loop
rms = 0;
for( i=0 ; i < L ; i++ ) {
acc.re += (pt_sample->re) * (*pt_coeffs );
acc.im += (pt_sample->im) * (*pt_coeffs );
rms += (pt_sample->re)*(pt_sample->re) + (pt_sample->im)*(pt_sample->im);
pt_sample++;
pt_coeffs++;
}
f->rms = sqrt( rms / L );
return( acc );
}
TYPECPX m_Osc1;
double m_OscCos, m_OscSin;
int nco_enabled;
#define B_SIZE (512)
#define COMP_ATTAK ( exp(-1/48.0)) /* 0.1 ms */
#define COMP_RELEASE (exp(-1/(30*480.0))) /* 300 ms */
#define threshold (.25)
void ssb(float in, int USB, float* out_I, float* out_Q)
{
static float y_n1 = 0;
static float x_n1 = 0;
float y, Imix, Qmix, OscGn;
static float I=0;
static float Q=0;
static int OL = 3;
// RingBuffer management
static int b_start = 0;
static int b_end = 0;
static float elems[B_SIZE]; // power of 2, approx 1ms at 48KHz
static int first = B_SIZE; // this says how many samples we wait before audio processing
static float env = 0;
float rms, theta, gain;
//---------------------------
int i;
TYPECPX dtmp, Osc, IQ;
OL++;
OL = OL % 4;
//---------- lowpass filter audio input
// suppress DC, high pass filter
// y[n] = x[n] - x[n-1] + alpha * y[n-1]
y = in - x_n1 + ALPHA_DC_REMOVE*y_n1;
x_n1 = in;
y_n1 = y;
// low pass filter y to keep only audio band
y = fir_filt( audio_fir, y );
#define AUDIO_COMPRESSOR //???
#ifdef AUDIO_COMPRESSOR //???
//----------- audio compressor
//--- code inspired from http://www.musicdsp.org/showone.php?id=169
// store in our ring buffer
if( b_end != (b_start ^ B_SIZE )) { // ring buffer not full
elems[b_end & (B_SIZE-1)] = y; // append at the end
if( b_end == (b_start ^ B_SIZE )) {
b_start = (b_start+1)&(2*B_SIZE-1);
}
b_end = (b_end+1)&(2*B_SIZE-1);
}
// wait to have at least 2ms before starting
if( first > 0 ) {
first--;
*out_I = 0;
*out_Q = 0;
return;
}
// compute RMS power in buffer
rms = 0;
for( i=0 ; i < B_SIZE ; i++ ) {
rms += elems[i] * elems[i];
}
rms = sqrt( rms / B_SIZE );
theta = rms > env ? COMP_ATTAK : COMP_RELEASE;
env = (1-theta) * rms + theta * env;
gain = 1;
if( env > threshold ) {
gain = 1 - (env - threshold);
}
// retrieve the oldest sample
y = elems[b_start&(B_SIZE-1)];
b_start = (b_start+1)&(2*B_SIZE-1);
// apply compressor gain
//printf("%f,%f\n", env, gain );
y *= gain ; // To enable compressor
#endif
//----------- SSB modulator stage
// decimation by 4
if( OL == 0 ) {
// we come here 1/4 of time
// pass audio sample to delay line, pass band filter
I = fir_filt( delay, y );
// pass audio sample to hilbert transform to shift 90 degrees
Q = fir_filt( hilbert, y );
}
IQ.re = I;
IQ.im = USB * Q;
// interpolation by 4
dtmp = cfir_filt( interpolateIQ, IQ );
// shift in freq if enabled (see ssb_init )
if( nco_enabled ) {
// our SSB signal is now centered at 0
// update our NCO for shift
Osc.re = m_Osc1.re * m_OscCos - m_Osc1.im * m_OscSin;
Osc.im = m_Osc1.im * m_OscCos + m_Osc1.re * m_OscSin;
OscGn = 1.95 - (m_Osc1.re*m_Osc1.re + m_Osc1.im*m_Osc1.im);
m_Osc1.re = OscGn * Osc.re;
m_Osc1.im = OscGn * Osc.im;
//Cpx multiply by shift OL
Imix = ((dtmp.re * Osc.re) - (dtmp.im * Osc.im));
Qmix = ((dtmp.re * Osc.im) + (dtmp.im * Osc.re));
*out_I = Imix;
*out_Q = Qmix;
} else {
*out_I = dtmp.re;
*out_Q = dtmp.im;
}
}
#define SAMPLE_RATE (48000.0f)
void ssb_init( float shift_carrier)
{
double m_NcoInc;
float a[83];
float b[89];
float c[89];
/*
* Kaiser Window FIR Filter
* Passband: 0.0 - 3000.0 Hz
* Order: 83
* Transition band: 3000.0 Hz
* Stopband attenuation: 80.0 dB
*/
a[0] = -1.7250879E-5f;
a[1] = -4.0276995E-5f;
a[2] = -5.6314686E-5f;
a[3] = -4.0164417E-5f;
a[4] = 3.0053454E-5f;
a[5] = 1.5370155E-4f;
a[6] = 2.9180944E-4f;
a[7] = 3.6717512E-4f;
a[8] = 2.8903902E-4f;
a[9] = 3.1934875E-11f;
a[10] = -4.716546E-4f;
a[11] = -9.818495E-4f;
a[12] = -0.001290066f;
a[13] = -0.0011395542f;
a[14] = -3.8172887E-4f;
a[15] = 9.0173044E-4f;
a[16] = 0.0023420234f;
a[17] = 0.003344623f;
a[18] = 0.003282209f;
a[19] = 0.0017731993f;
a[20] = -0.0010558856f;
a[21] = -0.004450674f;
a[22] = -0.0071515352f;
a[23] = -0.007778209f;
a[24] = -0.0053855875f;
a[25] = -2.6561373E-10f;
a[26] = 0.0070972904f;
a[27] = 0.013526209f;
a[28] = 0.016455514f;
a[29] = 0.013607533f;
a[30] = 0.0043148645f;
a[31] = -0.009761283f;
a[32] = -0.02458954f;
a[33] = -0.03455451f;
a[34] = -0.033946108f;
a[35] = -0.018758629f;
a[36] = 0.011756961f;
a[37] = 0.054329403f;
a[38] = 0.10202855f;
a[39] = 0.14574805f;
a[40] = 0.17644218f;
a[41] = 0.18748334f;
a[42] = 0.17644218f;
a[43] = 0.14574805f;
a[44] = 0.10202855f;
a[45] = 0.054329403f;
a[46] = 0.011756961f;
a[47] = -0.018758629f;
a[48] = -0.033946108f;
a[49] = -0.03455451f;
a[50] = -0.02458954f;
a[51] = -0.009761283f;
a[52] = 0.0043148645f;
a[53] = 0.013607533f;
a[54] = 0.016455514f;
a[55] = 0.013526209f;
a[56] = 0.0070972904f;
a[57] = -2.6561373E-10f;
a[58] = -0.0053855875f;
a[59] = -0.007778209f;
a[60] = -0.0071515352f;
a[61] = -0.004450674f;
a[62] = -0.0010558856f;
a[63] = 0.0017731993f;
a[64] = 0.003282209f;
a[65] = 0.003344623f;
a[66] = 0.0023420234f;
a[67] = 9.0173044E-4f;
a[68] = -3.8172887E-4f;
a[69] = -0.0011395542f;
a[70] = -0.001290066f;
a[71] = -9.818495E-4f;
a[72] = -4.716546E-4f;
a[73] = 3.1934875E-11f;
a[74] = 2.8903902E-4f;
a[75] = 3.6717512E-4f;
a[76] = 2.9180944E-4f;
a[77] = 1.5370155E-4f;
a[78] = 3.0053454E-5f;
a[79] = -4.0164417E-5f;
a[80] = -5.6314686E-5f;
a[81] = -4.0276995E-5f;
a[82] = -1.7250879E-5f;
/*
* Kaiser Window FIR Filter
* Passband: 0.0 - 1350.0 Hz
* modulation freq: 1650Hz
* Order: 88
* Transition band: 500.0 Hz
* Stopband attenuation: 60.0 dB
*/
b[0] = -2.081541E-4f;
b[1] = -3.5587244E-4f;
b[2] = -5.237722E-5f;
b[3] = -1.00883444E-4f;
b[4] = -8.27162E-4f;
b[5] = -7.391658E-4f;
b[6] = 9.386093E-5f;
b[7] = -6.221307E-4f;
b[8] = -0.0019506976f;
b[9] = -8.508009E-4f;
b[10] = 2.8596455E-4f;
b[11] = -0.002028003f;
b[12] = -0.003321186f;
b[13] = -2.7830937E-4f;
b[14] = 2.7148606E-9f;
b[15] = -0.004654892f;
b[16] = -0.0041854046f;
b[17] = 0.001115112f;
b[18] = -0.0017027275f;
b[19] = -0.008291345f;
b[20] = -0.0034240147f;
b[21] = 0.0027767413f;
b[22] = -0.005873899f;
b[23] = -0.011811939f;
b[24] = -2.075215E-8f;
b[25] = 0.003209243f;
b[26] = -0.0131212445f;
b[27] = -0.013072912f;
b[28] = 0.0064319638f;
b[29] = 1.0081245E-8f;
b[30] = -0.023050211f;
b[31] = -0.009034872f;
b[32] = 0.015074444f;
b[33] = -0.010180626f;
b[34] = -0.034043692f;
b[35] = 0.004729156f;
b[36] = 0.024004854f;
b[37] = -0.033643555f;
b[38] = -0.043601833f;
b[39] = 0.04075407f;
b[40] = 0.03076061f;
b[41] = -0.10492244f;
b[42] = -0.049181364f;
b[43] = 0.30635652f;
b[44] = 0.5324795f;
b[45] = 0.30635652f;
b[46] = -0.049181364f;
b[47] = -0.10492244f;
b[48] = 0.03076061f;
b[49] = 0.04075407f;
b[50] = -0.043601833f;
b[51] = -0.033643555f;
b[52] = 0.024004854f;
b[53] = 0.004729156f;
b[54] = -0.034043692f;
b[55] = -0.010180626f;
b[56] = 0.015074444f;
b[57] = -0.009034872f;
b[58] = -0.023050211f;
b[59] = 1.0081245E-8f;
b[60] = 0.0064319638f;
b[61] = -0.013072912f;
b[62] = -0.0131212445f;
b[63] = 0.003209243f;
b[64] = -2.075215E-8f;
b[65] = -0.011811939f;
b[66] = -0.005873899f;
b[67] = 0.0027767413f;
b[68] = -0.0034240147f;
b[69] = -0.008291345f;
b[70] = -0.0017027275f;
b[71] = 0.001115112f;
b[72] = -0.0041854046f;
b[73] = -0.004654892f;
b[74] = 2.7148606E-9f;
b[75] = -2.7830937E-4f;
b[76] = -0.003321186f;
b[77] = -0.002028003f;
b[78] = 2.8596455E-4f;
b[79] = -8.508009E-4f;
b[80] = -0.0019506976f;
b[81] = -6.221307E-4f;
b[82] = 9.386093E-5f;
b[83] = -7.391658E-4f;
b[84] = -8.27162E-4f;
b[85] = -1.00883444E-4f;
b[86] = -5.237722E-5f;
b[87] = -3.5587244E-4f;
b[88] = -2.081541E-4f;
/*
* Kaiser Window FIR Filter
*
* Filter type: Q-filter
* Passband: 0.0 - 1350.0 Hz
* modulation freq: 1650Hz
* with +90 degree pahse shift
* Order: 88
* Transition band: 500.0 Hz
* Stopband attenuation: 60.0 dB
*/
c[0] = 6.767926E-5f;
c[1] = -2.1822347E-4f;
c[2] = -3.3091355E-4f;
c[3] = 1.1819744E-4f;
c[4] = 2.1773627E-9f;
c[5] = -8.6602167E-4f;
c[6] = -5.9300865E-4f;
c[7] = 3.814961E-4f;
c[8] = -6.342388E-4f;
c[9] = -0.00205537f;
c[10] = -5.616135E-4f;
c[11] = 4.8721067E-4f;
c[12] = -0.002414588f;
c[13] = -0.003538588f;
c[14] = -2.7166707E-9f;
c[15] = -3.665928E-4f;
c[16] = -0.0057645175f;
c[17] = -0.004647882f;
c[18] = 8.681589E-4f;
c[19] = -0.0034366683f;
c[20] = -0.010545009f;
c[21] = -0.0045342376f;
c[22] = 9.309649E-4f;
c[23] = -0.01009504f;
c[24] = -0.015788108f;
c[25] = -0.0027427748f;
c[26] = -0.0020795742f;
c[27] = -0.021347176f;
c[28] = -0.019808702f;
c[29] = -4.1785704E-9f;
c[30] = -0.011752444f;
c[31] = -0.037658f;
c[32] = -0.020762002f;
c[33] = 8.017756E-4f;
c[34] = -0.03406628f;
c[35] = -0.060129803f;
c[36] = -0.01745214f;
c[37] = -0.008082453f;
c[38] = -0.08563026f;
c[39] = -0.09845453f;
c[40] = -0.010001372f;
c[41] = -0.06433928f;
c[42] = -0.31072536f;
c[43] = -0.35893586f;
c[44] = 0.0f;
c[45] = 0.35893586f;
c[46] = 0.31072536f;
c[47] = 0.06433928f;
c[48] = 0.010001372f;
c[49] = 0.09845453f;
c[50] = 0.08563026f;
c[51] = 0.008082453f;
c[52] = 0.01745214f;
c[53] = 0.060129803f;
c[54] = 0.03406628f;
c[55] = -8.017756E-4f;
c[56] = 0.020762002f;
c[57] = 0.037658f;
c[58] = 0.011752444f;
c[59] = 4.1785704E-9f;
c[60] = 0.019808702f;
c[61] = 0.021347176f;
c[62] = 0.0020795742f;
c[63] = 0.0027427748f;
c[64] = 0.015788108f;
c[65] = 0.01009504f;
c[66] = -9.309649E-4f;
c[67] = 0.0045342376f;
c[68] = 0.010545009f;
c[69] = 0.0034366683f;
c[70] = -8.681589E-4f;
c[71] = 0.004647882f;
c[72] = 0.0057645175f;
c[73] = 3.665928E-4f;
c[74] = 2.7166707E-9f;
c[75] = 0.003538588f;
c[76] = 0.002414588f;
c[77] = -4.8721067E-4f;
c[78] = 5.616135E-4f;
c[79] = 0.00205537f;
c[80] = 6.342388E-4f;
c[81] = -3.814961E-4f;
c[82] = 5.9300865E-4f;
c[83] = 8.6602167E-4f;
c[84] = -2.1773627E-9f;
c[85] = -1.1819744E-4f;
c[86] = 3.3091355E-4f;
c[87] = 2.1822347E-4f;
c[88] = -6.767926E-5f;
audio_fir = init_fir( 83, a );
hilbert = init_fir( 89, c );
delay = init_fir( 89, b );
interpolateIQ = init_cfir( 83, a );
nco_enabled = 0 ;
if( abs(shift_carrier) > 0 ) {
m_NcoInc = (2.0 * 3.14159265358979323846)*shift_carrier/SAMPLE_RATE;
m_OscCos = cos(m_NcoInc);
m_OscSin = sin(m_NcoInc);
m_Osc1.re = 1.0; //initialize unit vector that will get rotated
m_Osc1.im = 0.0;
nco_enabled = 1;
}
}

View File

@@ -1,41 +0,0 @@
//==========================================================================================
// + + + This Software is released under the "Simplified BSD License" + + +
// Copyright 2014 F4GKR Sylvain AZARIAN . All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Sylvain AZARIAN F4GKR ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Sylvain AZARIAN OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Sylvain AZARIAN F4GKR.
//==========================================================================================
#ifndef SSBGEN_H
#define SSBGEN_H
// pour USB : mettre USB = -1
// pour LSB : mettre USB = 1 ;
#define MODULE_SSB_USB (-1)
#define MODULE_SSB_LSB (1)
void ssb(float in, int USB, float* out_I, float* out_Q);
// de combien on decale la porteuse (+ ou - )
void ssb_init(float shift_carrier);
#endif

View File

@@ -1,105 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include "ssb_gen.h"
#include <sndfile.h>
#define BUFFER_LEN 1024*8
// Test program using SNDFILE
// see http://www.mega-nerd.com/libsndfile/api.html for API
int main(int argc, char **argv)
{
float data [2*BUFFER_LEN];
float data_filtered[2*BUFFER_LEN]; // we generate complex I/Q samples
SNDFILE *infile, *outfile;
SF_INFO sfinfo;
SF_INFO sf_out;
int readcount, nb_samples;
char *infilename;
char *outfilename;
int k;
float x,I,Q;
if( argc < 2 ) {
printf("Usage : %s in.wav [out.wav]\n", argv[0]);
return(1);
}
infilename = argv[1];
if( argc == 3 ) {
outfilename = argv[2];
} else {
outfilename = (char *)malloc( 128 );
sprintf( outfilename, "%s", "out.wav");
}
if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))
{
/* Open failed so print an error message. */
printf ("Not able to open input file %s.\n", infilename);
/* Print the error message from libsndfile. */
puts (sf_strerror (NULL));
return 1;
}
if( sfinfo.samplerate != 48000 ) {
printf("Input rate must be 48K.\n");
return 1;
}
memcpy( (void *)&sf_out, (void *)&sfinfo, sizeof( SF_INFO ));
sf_out.channels = 2;
//sf_out.samplerate = sfinfo.samplerate/3;
/* Open the output file. */
if (! (outfile = sf_open (outfilename, SFM_WRITE, &sf_out)))
{
printf ("Not able to open output file %s.\n", outfilename);
puts (sf_strerror (NULL));
return 1;
}
/** **/
printf ("Reading file : %s\n", infilename );
printf ("Sample Rate : %d\n", sfinfo.samplerate);
printf ("Channels : %d\n", sfinfo.channels);
printf ("----------------------------------------\n");
printf ("Writing file : %s\n", outfilename );
printf ("Channels : %d\n", sf_out.channels);
// la porteuse SSB est décalée de +1K
ssb_init( 1000 );
/* While there are.frames in the input file, read them, process
** them and write them to the output file.
*/
while ((readcount = sf_readf_float(infile, data, BUFFER_LEN)))
{
nb_samples = readcount / sfinfo.channels;
for( k=0 ; k < nb_samples ; k++ ) {
x = data[k*sfinfo.channels];
if( sfinfo.channels == 2 ) {
// stereo file, avg left + right
x += data[k*sfinfo.channels+1];
x /= 2;
}
// voir ssb_gen.h, mettre MODULE_SSB_LSB pour LSB module
ssb( x, MODULE_SSB_USB , &I, &Q );
data_filtered[2*k ] = I; //I and Q seems to be between 0 and 0.5
data_filtered[2*k+1] = Q;
/* // FOR COMPRESSOR *2
data_filtered[2*k ] = I * 2; //I and Q seems to be between 0 and 0.5
data_filtered[2*k+1] = Q * 2;
*/
}
sf_write_float(outfile, data_filtered, 2*nb_samples );
}
/* Close input and output files. */
sf_close (infile);
sf_close (outfile);
return 0;
}

View File

@@ -1,172 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
int FilePicture;
int FileFreqTiming;
static double GlobalTuningFrequency=00000.0;
void playtone(double Frequency,uint32_t Timing)
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
samplerf_t RfSample;
RfSample.Frequency=GlobalTuningFrequency+Frequency;
RfSample.WaitForThisSample=Timing*100L; //en 100 de nanosecond
//printf("Freq =%f Timing=%d\n",RfSample.Frequency,RfSample.WaitForThisSample);
if (write(FileFreqTiming,&RfSample,sizeof(samplerf_t)) != sizeof(samplerf_t)) {
fprintf(stderr, "Unable to write sample");
}
}
void addvisheader()
{
printf( "Adding VIS header to audio data.\n" ) ;
// bit of silence
playtone( 0 , 5000000) ;
// attention tones
playtone( 1900 , 100000 ) ; // you forgot this one
playtone( 1500 , 1000000) ;
playtone( 1900 , 1000000) ;
playtone( 1500 , 1000000) ;
playtone( 2300 , 1000000) ;
playtone( 1500 , 1000000) ;
playtone( 2300 , 1000000) ;
playtone( 1500 , 1000000) ;
// VIS lead, break, mid, start
playtone( 1900 , 3000000) ;
playtone( 1200 , 100000) ;
//playtone( 1500 , 300000 ) ;
playtone( 1900 , 3000000) ;
playtone( 1200 , 300000) ;
// VIS data bits (Martin 1)
playtone( 1300 , 300000) ;
playtone( 1300 , 300000) ;
playtone( 1100 , 300000) ;
playtone( 1100 , 300000) ;
playtone( 1300 , 300000) ;
playtone( 1100 , 300000) ;
playtone( 1300 , 300000 ) ;
playtone( 1100 , 300000 ) ;
// VIS stop
playtone( 1200 , 300000 ) ;
printf( "Done adding VIS header to audio data.\n" ) ;
} // end addvisheader
void addvistrailer ()
{
printf( "Adding VIS trailer to audio data.\n" ) ;
playtone( 2300 , 3000000 ) ;
playtone( 1200 , 100000 ) ;
playtone( 2300 , 1000000 ) ;
playtone( 1200 , 300000 ) ;
// bit of silence
playtone( 0 , 5000000 ) ;
printf( "Done adding VIS trailer to audio data.\n" ) ;
}
void ProcessMartin1()
{
static uint32_t FrequencyMartin1[3]={1200,1500,1500};
static uint32_t TimingMartin1[3]={48620,5720,4576};
int EndOfPicture=0;
int NbRead=0;
int VIS=1;
static unsigned char Line[320*3];
int Row;
addvisheader();
addvistrailer();
while(EndOfPicture==0)
{
NbRead=read(FilePicture,Line,320*3);
if(NbRead!=320*3) EndOfPicture=1;
//MARTIN 1 Implementation
//Horizontal SYNC
playtone((double)FrequencyMartin1[0],TimingMartin1[0]);
//Separator Tone
playtone((double)FrequencyMartin1[1],TimingMartin1[1]);
for(Row=0;Row<320;Row++)
{
playtone((double)FrequencyMartin1[1]+Line[Row*3+1]*800/256,TimingMartin1[2]);
}
playtone((double)FrequencyMartin1[1],TimingMartin1[1]);
//Blue
for(Row=0;Row<320;Row++)
{
playtone((double)FrequencyMartin1[1]+Line[Row*3+2]*800/256,TimingMartin1[2]);
}
playtone((double)FrequencyMartin1[1],TimingMartin1[1]);
//Red
for(Row=0;Row<320;Row++)
{
playtone((double)FrequencyMartin1[1]+Line[Row*3]*800/256,TimingMartin1[2]);
}
playtone((double)FrequencyMartin1[1],TimingMartin1[1]);
}
}
int main(int argc, char **argv)
{
if (argc > 2)
{
char *sFilePicture=(char *)argv[1];
FilePicture = open(argv[1], O_RDONLY);
char *sFileFreqTiming=(char *)argv[2];
FileFreqTiming = open(argv[2], O_WRONLY|O_CREAT, 0644);
}
else
{
printf("usage : pisstv picture.rgb outputfreq.bin\n");
exit(0);
}
ProcessMartin1();
/*int i;
for(i=0;i<320*240;i++)
{
playtone(1200,5720);
playtone(0,5720);
}*/
close(FilePicture);
close(FileFreqTiming);
return 0;
}

View File

@@ -1,3 +1,3 @@
./pifm sampleaudio.wav fm.ft
sudo ./rpitx -m RF -i fm.ft -f 433900 -l
sudo ./rpitx -m RF -i fm.ft -f 89000 -l -a 14 -c 1