mirror of
https://github.com/F5OEO/rpitx.git
synced 2026-03-11 10:57:01 +01:00
Still migrate
This commit is contained in:
121
am/piam.c
121
am/piam.c
@@ -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;
|
||||
}
|
||||
254
dcf77/pidcf77.c
254
dcf77/pidcf77.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
140
drone/drone.c
140
drone/drone.c
@@ -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
109
fm/pifm.c
@@ -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;
|
||||
}
|
||||
379
fsq/pifsq.c
379
fsq/pifsq.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 **************************************
|
||||
515
opera/opera.c
515
opera/opera.c
@@ -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 ********************************
|
||||
22
src/LICENSE
22
src/LICENSE
@@ -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.
|
||||
|
||||
80
src/Makefile
80
src/Makefile
@@ -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 !!!)
|
||||
119
src/RpiDma.c
119
src/RpiDma.c
@@ -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;
|
||||
}
|
||||
128
src/RpiDma.h
128
src/RpiDma.h
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
src/RpiGpio.h
110
src/RpiGpio.h
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
}
|
||||
@@ -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;}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
253
src/dma.cpp
253
src/dma.cpp
@@ -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
121
src/dma.h
@@ -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
|
||||
68
src/dsp.cpp
68
src/dsp.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
31
src/dsp.h
31
src/dsp.h
@@ -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
|
||||
BIN
src/dt-blob.bin
BIN
src/dt-blob.bin
Binary file not shown.
1716
src/dt-blob.dts
1716
src/dt-blob.dts
File diff suppressed because it is too large
Load Diff
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
114
src/fskburst.cpp
114
src/fskburst.cpp
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
669
src/gpio.cpp
669
src/gpio.cpp
@@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
284
src/gpio.h
284
src/gpio.h
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
280
src/mailbox.c
280
src/mailbox.c
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
BIN
src/v2rpitx
BIN
src/v2rpitx
Binary file not shown.
402
src/v2rpitx.cpp
402
src/v2rpitx.cpp
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
589
ssbgen/ssb_gen.c
589
ssbgen/ssb_gen.c
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
172
sstv/pisstv.c
172
sstv/pisstv.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user