mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-04-23 15:38:45 +02:00
add sddc source prototype + add new ATV decoder + fix windows builds
This commit is contained in:
parent
aa2b4b1c58
commit
e75cc7be6f
65
decoder_modules/atv_decoder/src/amplitude.h
Normal file
65
decoder_modules/atv_decoder/src/amplitude.h
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include <dsp/processor.h>
|
||||
#include <dsp/math/fast_atan2.h>
|
||||
#include <dsp/math/hz_to_rads.h>
|
||||
#include <dsp/math/normalize_phase.h>
|
||||
|
||||
namespace dsp::demod {
|
||||
class Amplitude : public Processor<complex_t, float> {
|
||||
using base_type = Processor<complex_t, float>;
|
||||
public:
|
||||
Amplitude() {}
|
||||
|
||||
Amplitude(stream<complex_t>* in, double deviation) { init(in, deviation); }
|
||||
|
||||
Amplitude(stream<complex_t>* in, double deviation, double samplerate) { init(in, deviation, samplerate); }
|
||||
|
||||
|
||||
virtual void init(stream<complex_t>* in, double deviation) {
|
||||
_invDeviation = 1.0 / deviation;
|
||||
base_type::init(in);
|
||||
}
|
||||
|
||||
virtual void init(stream<complex_t>* in, double deviation, double samplerate) {
|
||||
init(in, math::hzToRads(deviation, samplerate));
|
||||
}
|
||||
|
||||
void setDeviation(double deviation) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_invDeviation = 1.0 / deviation;
|
||||
}
|
||||
|
||||
void setDeviation(double deviation, double samplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_invDeviation = 1.0 / math::hzToRads(deviation, samplerate);
|
||||
}
|
||||
|
||||
inline int process(int count, complex_t* in, float* out) {
|
||||
volk_32fc_magnitude_32f(out, (lv_32fc_t*)in, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
phase = 0.0f;
|
||||
}
|
||||
|
||||
int run() {
|
||||
int count = base_type::_in->read();
|
||||
if (count < 0) { return -1; }
|
||||
|
||||
process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||
|
||||
base_type::_in->flush();
|
||||
if (!base_type::out.swap(count)) { return -1; }
|
||||
return count;
|
||||
}
|
||||
|
||||
protected:
|
||||
float _invDeviation;
|
||||
float phase = 0.0f;
|
||||
};
|
||||
}
|
176
decoder_modules/atv_decoder/src/burst_blanking.txt
Normal file
176
decoder_modules/atv_decoder/src/burst_blanking.txt
Normal file
@ -0,0 +1,176 @@
|
||||
617 + 6 -> I
|
||||
|
||||
304 + 6 -> II
|
||||
|
||||
616 + 6 -> III
|
||||
|
||||
305 + 6 -> IV
|
||||
|
||||
|
||||
|
||||
304
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
|
||||
616
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
313
|
||||
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
0
|
||||
|
||||
304
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
616
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
313
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
0
|
||||
304
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
616
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
313
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
0
|
||||
304
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
616
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
313
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
||||
0
|
||||
304
|
||||
305
|
||||
306
|
||||
307
|
||||
308
|
||||
309
|
||||
310
|
||||
311
|
||||
312
|
||||
616
|
||||
617
|
||||
618
|
||||
619
|
||||
620
|
||||
621
|
||||
622
|
||||
623
|
||||
624
|
@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
#include <dsp/loop/pll.h>
|
||||
#include "chrominance_filter.h"
|
||||
|
||||
// TODO: Should be 60 but had to try something
|
||||
#define BURST_START (63+CHROMA_FIR_DELAY)
|
||||
#define BURST_END (BURST_START+28)
|
||||
|
||||
#define A_PHASE ((135.0/180.0)*FL_M_PI)
|
||||
#define B_PHASE ((-135.0/180.0)*FL_M_PI)
|
||||
|
||||
namespace dsp::loop {
|
||||
class ChromaPLL : public PLL {
|
||||
using base_type = PLL;
|
||||
public:
|
||||
ChromaPLL() {}
|
||||
|
||||
ChromaPLL(stream<complex_t>* in, double bandwidth, double initPhase = 0.0, double initFreq = 0.0, double minFreq = -FL_M_PI, double maxFreq = FL_M_PI) {
|
||||
base_type::init(in, bandwidth, initFreq, initPhase, minFreq, maxFreq);
|
||||
}
|
||||
|
||||
inline int process(int count, complex_t* in, complex_t* out, bool aphase = false) {
|
||||
// Process the pre-burst section
|
||||
for (int i = 0; i < BURST_START; i++) {
|
||||
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||
pcl.advancePhase();
|
||||
}
|
||||
|
||||
// Process the burst itself
|
||||
if (aphase) {
|
||||
for (int i = BURST_START; i < BURST_END; i++) {
|
||||
complex_t outVal = in[i] * math::phasor(-pcl.phase);
|
||||
out[i] = outVal;
|
||||
pcl.advance(math::normalizePhase(outVal.phase() - A_PHASE));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = BURST_START; i < BURST_END; i++) {
|
||||
complex_t outVal = in[i] * math::phasor(-pcl.phase);
|
||||
out[i] = outVal;
|
||||
pcl.advance(math::normalizePhase(outVal.phase() - B_PHASE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process the post-burst section
|
||||
for (int i = BURST_END; i < count; i++) {
|
||||
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||
pcl.advancePhase();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inline int processBlank(int count, complex_t* in, complex_t* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||
pcl.advancePhase();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
#pragma once
|
||||
#include <dsp/types.h>
|
||||
|
||||
inline const dsp::complex_t CHROMA_FIR[] = {
|
||||
{-0.000005461290583903, -0.000011336784355655},
|
||||
{ 0.000020060944485414, 0.000009851315045203},
|
||||
{-0.000034177222729438, 0.000007245841504981},
|
||||
{ 0.000027694034878705, -0.000033114740542635},
|
||||
{-0.000001217597841648, 0.000039141482370942},
|
||||
{-0.000008324593371228, -0.000011315001355976},
|
||||
{-0.000038085228233509, -0.000010585909953738},
|
||||
{ 0.000114833396071141, -0.000047778708840608},
|
||||
{-0.000115428390169113, 0.000205816198882814},
|
||||
{-0.000055467806072871, -0.000356692479491626},
|
||||
{ 0.000349316846854190, 0.000326162940234916},
|
||||
{-0.000558465829929114, -0.000048001521408724},
|
||||
{ 0.000488176200631416, -0.000319593757302922},
|
||||
{-0.000169437838021935, 0.000501610900725908},
|
||||
{-0.000131793335799502, -0.000373003580727547},
|
||||
{ 0.000166817395492786, 0.000105930895534474},
|
||||
{ 0.000030499908326112, -0.000003048682668943},
|
||||
{-0.000174999505027919, 0.000168008090089458},
|
||||
{ 0.000054431163395030, -0.000385174790951272},
|
||||
{ 0.000215876012859739, 0.000372695852521209},
|
||||
{-0.000325534912280750, -0.000130173041693966},
|
||||
{ 0.000154951430569290, -0.000045395998708328},
|
||||
{ 0.000054324657659002, -0.000076028700470037},
|
||||
{ 0.000015664427565764, 0.000348002612845696},
|
||||
{-0.000345943017888332, -0.000402175417043307},
|
||||
{ 0.000568731727879741, 0.000112347863435682},
|
||||
{-0.000416485880859085, 0.000211750352828909},
|
||||
{ 0.000087462353623011, -0.000188197153014309},
|
||||
{-0.000032082305030264, -0.000136804226080664},
|
||||
{ 0.000379089999045955, 0.000303466839685362},
|
||||
{-0.000726760198519770, -0.000007022279302816},
|
||||
{ 0.000619888661818195, -0.000476871323359809},
|
||||
{-0.000151885493742993, 0.000595641190573181},
|
||||
{-0.000100626407015494, -0.000227947144491108},
|
||||
{-0.000201935458823941, -0.000107628631934340},
|
||||
{ 0.000680260922139900, -0.000120771182888852},
|
||||
{-0.000666108629277491, 0.000744775901128973},
|
||||
{ 0.000067236591919755, -0.001044125966364420},
|
||||
{ 0.000447037274751822, 0.000651912509450913},
|
||||
{-0.000262675893448686, -0.000082499729563337},
|
||||
{-0.000349821460486320, 0.000132102793530818},
|
||||
{ 0.000507024815168287, -0.000837598610490618},
|
||||
{ 0.000163814255478652, 0.001346530693477834},
|
||||
{-0.000970457632383793, -0.000968411010101160},
|
||||
{ 0.000974834882891140, 0.000116507082762032},
|
||||
{-0.000225464280571542, 0.000137131865995708},
|
||||
{-0.000211542240694642, 0.000563783548428947},
|
||||
{-0.000414412310798766, -0.001309793399193736},
|
||||
{ 0.001497010004594478, 0.001021907858926259},
|
||||
{-0.001752019159639658, 0.000116536066154131},
|
||||
{ 0.000872822027879430, -0.000783952720205569},
|
||||
{-0.000032439446797970, 0.000184988059956734},
|
||||
{ 0.000446259382722895, 0.000833040920509238},
|
||||
{-0.001741577737284306, -0.000764423771425237},
|
||||
{ 0.002306569133792772, -0.000593352416441601},
|
||||
{-0.001336084746214192, 0.001744394557524181},
|
||||
{-0.000015810020735495, -0.001342809547658260},
|
||||
{ 0.000007636494885364, 0.000009498318627546},
|
||||
{ 0.001403876768349702, 0.000326101441888391},
|
||||
{-0.002351020828600226, 0.001098649819278302},
|
||||
{ 0.001389314639579544, -0.002746943712072884},
|
||||
{ 0.000526319899588909, 0.002635084366837732},
|
||||
{-0.001109526585744687, -0.000950323796527721},
|
||||
{-0.000307792427984886, -0.000013203419520794},
|
||||
{ 0.001737955094951111, -0.001247368808692850},
|
||||
{-0.000974502437588420, 0.003352512117661680},
|
||||
{-0.001462571137390936, -0.003635296917435679},
|
||||
{ 0.002783459090201693, 0.001604420226187745},
|
||||
{-0.001471518558760170, 0.000211117948702137},
|
||||
{-0.000575340825070194, 0.000601820846100026},
|
||||
{ 0.000302090333345692, -0.003088058972305493},
|
||||
{ 0.002496092353182990, 0.003912508340989065},
|
||||
{-0.004645661091012423, -0.001630427298020200},
|
||||
{ 0.003556824805628799, -0.001209822327859352},
|
||||
{-0.000744999556260706, 0.001143238699138109},
|
||||
{ 0.000144278726929409, 0.001638049051599065},
|
||||
{-0.003025291044450178, -0.003226370992887968},
|
||||
{ 0.006047866290490120, 0.000927406808799887},
|
||||
{-0.005338456415106141, 0.003008811999350399},
|
||||
{ 0.001642959659014839, -0.003972384205231079},
|
||||
{ 0.000273874932822212, 0.000977326273749033},
|
||||
{ 0.002315022846573390, 0.001695671268241410},
|
||||
{-0.006240953957978884, 0.000207330368698293},
|
||||
{ 0.006164252120861735, -0.005177351717451013},
|
||||
{-0.001560310257561104, 0.007437030759707700},
|
||||
{-0.002131333814462852, -0.004317129694157112},
|
||||
{ 0.000280518918541908, 0.000134405998842553},
|
||||
{ 0.004612116481180659, -0.001024468120657814},
|
||||
{-0.005599300279638699, 0.006828277067771868},
|
||||
{ 0.000228879728552504, -0.010675998154712657},
|
||||
{ 0.005692081512980654, 0.007582243186569848},
|
||||
{-0.005100500569859509, -0.001364751685737153},
|
||||
{-0.000902490398043454, 0.000385770160220703},
|
||||
{ 0.003673858819546609, -0.006701685283451640},
|
||||
{ 0.002079056046131593, 0.012568579063417429},
|
||||
{-0.010730008156911677, -0.009826454574016218},
|
||||
{ 0.012092401380903161, 0.000921764172237851},
|
||||
{-0.004714530989129091, 0.003151948807627123},
|
||||
{-0.001055930168838909, 0.003228576712467020},
|
||||
{-0.004343270165991213, -0.011924332879354394},
|
||||
{ 0.016499994418955999, 0.010255324919126899},
|
||||
{-0.021047239750251585, 0.002309419513135448},
|
||||
{ 0.011855513874047341, -0.011604071033866310},
|
||||
{-0.000777842281358575, 0.005916341648175263},
|
||||
{ 0.004380939277688377, 0.007397670455730446},
|
||||
{-0.021891594662401131, -0.008509480947490166},
|
||||
{ 0.032787638290674201, -0.009950745850861956},
|
||||
{-0.021022579272463194, 0.030030850567389102},
|
||||
{-0.001508145650189953, -0.027571914870304640},
|
||||
{ 0.004056649693022923, 0.004624901687718579},
|
||||
{ 0.025728742586666287, 0.004824671348397606},
|
||||
{-0.058002700931665603, 0.030198618296813803},
|
||||
{ 0.043631619628438784, -0.096308304333327280},
|
||||
{ 0.033451363423624300, 0.136687079396426990},
|
||||
{-0.129387018420204200, -0.101540513046619400},
|
||||
{ 0.172881344826560730, -0.000000000000005297},
|
||||
{-0.129387018420198010, 0.101540513046627330},
|
||||
{ 0.033451363423615862, -0.136687079396429050},
|
||||
{ 0.043631619628444723, 0.096308304333324601},
|
||||
{-0.058002700931667456, -0.030198618296810247},
|
||||
{ 0.025728742586665992, -0.004824671348399184},
|
||||
{ 0.004056649693022639, -0.004624901687718827},
|
||||
{-0.001508145650188251, 0.027571914870304734},
|
||||
{-0.021022579272465047, -0.030030850567387805},
|
||||
{ 0.032787638290674812, 0.009950745850859947},
|
||||
{-0.021891594662400610, 0.008509480947491507},
|
||||
{ 0.004380939277687923, -0.007397670455730714},
|
||||
{-0.000777842281358940, -0.005916341648175215},
|
||||
{ 0.011855513874048058, 0.011604071033865578},
|
||||
{-0.021047239750251731, -0.002309419513134139},
|
||||
{ 0.016499994418955360, -0.010255324919127926},
|
||||
{-0.004343270165990471, 0.011924332879354665},
|
||||
{-0.001055930168839110, -0.003228576712466955},
|
||||
{-0.004714530989129287, -0.003151948807626830},
|
||||
{ 0.012092401380903103, -0.000921764172238603},
|
||||
{-0.010730008156911072, 0.009826454574016881},
|
||||
{ 0.002079056046130817, -0.012568579063417559},
|
||||
{ 0.003673858819547020, 0.006701685283451416},
|
||||
{-0.000902490398043478, -0.000385770160220647},
|
||||
{-0.005100500569859424, 0.001364751685737466},
|
||||
{ 0.005692081512980187, -0.007582243186570198},
|
||||
{ 0.000228879728553163, 0.010675998154712643},
|
||||
{-0.005599300279639117, -0.006828277067771524},
|
||||
{ 0.004612116481180722, 0.001024468120657532},
|
||||
{ 0.000280518918541900, -0.000134405998842571},
|
||||
{-0.002131333814462586, 0.004317129694157243},
|
||||
{-0.001560310257561563, -0.007437030759707604},
|
||||
{ 0.006164252120862052, 0.005177351717450635},
|
||||
{-0.006240953957978898, -0.000207330368697911},
|
||||
{ 0.002315022846573286, -0.001695671268241552},
|
||||
{ 0.000273874932822152, -0.000977326273749050},
|
||||
{ 0.001642959659015084, 0.003972384205230976},
|
||||
{-0.005338456415106324, -0.003008811999350072},
|
||||
{ 0.006047866290490063, -0.000927406808800258},
|
||||
{-0.003025291044449980, 0.003226370992888153},
|
||||
{ 0.000144278726929308, -0.001638049051599074},
|
||||
{-0.000744999556260777, -0.001143238699138063},
|
||||
{ 0.003556824805628873, 0.001209822327859134},
|
||||
{-0.004645661091012323, 0.001630427298020484},
|
||||
{ 0.002496092353182751, -0.003912508340989219},
|
||||
{ 0.000302090333345882, 0.003088058972305475},
|
||||
{-0.000575340825070231, -0.000601820846099991},
|
||||
{-0.001471518558760183, -0.000211117948702046},
|
||||
{ 0.002783459090201593, -0.001604420226187919},
|
||||
{-0.001462571137390710, 0.003635296917435769},
|
||||
{-0.000974502437588628, -0.003352512117661619},
|
||||
{ 0.001737955094951189, 0.001247368808692742},
|
||||
{-0.000307792427984885, 0.000013203419520814},
|
||||
{-0.001109526585744628, 0.000950323796527789},
|
||||
{ 0.000526319899588746, -0.002635084366837765},
|
||||
{ 0.001389314639579712, 0.002746943712072799},
|
||||
{-0.002351020828600294, -0.001098649819278158},
|
||||
{ 0.001403876768349682, -0.000326101441888477},
|
||||
{ 0.000007636494885364, -0.000009498318627546},
|
||||
{-0.000015810020735412, 0.001342809547658261},
|
||||
{-0.001336084746214299, -0.001744394557524099},
|
||||
{ 0.002306569133792808, 0.000593352416441460},
|
||||
{-0.001741577737284259, 0.000764423771425344},
|
||||
{ 0.000446259382722843, -0.000833040920509266},
|
||||
{-0.000032439446797982, -0.000184988059956732},
|
||||
{ 0.000872822027879478, 0.000783952720205515},
|
||||
{-0.001752019159639665, -0.000116536066154024},
|
||||
{ 0.001497010004594416, -0.001021907858926351},
|
||||
{-0.000414412310798685, 0.001309793399193761},
|
||||
{-0.000211542240694677, -0.000563783548428934},
|
||||
{-0.000225464280571550, -0.000137131865995694},
|
||||
{ 0.000974834882891133, -0.000116507082762092},
|
||||
{-0.000970457632383734, 0.000968411010101219},
|
||||
{ 0.000163814255478569, -0.001346530693477844},
|
||||
{ 0.000507024815168339, 0.000837598610490586},
|
||||
{-0.000349821460486328, -0.000132102793530797},
|
||||
{-0.000262675893448681, 0.000082499729563353},
|
||||
{ 0.000447037274751782, -0.000651912509450940},
|
||||
{ 0.000067236591919819, 0.001044125966364416},
|
||||
{-0.000666108629277537, -0.000744775901128932},
|
||||
{ 0.000680260922139908, 0.000120771182888810},
|
||||
{-0.000201935458823935, 0.000107628631934352},
|
||||
{-0.000100626407015480, 0.000227947144491114},
|
||||
{-0.000151885493743030, -0.000595641190573172},
|
||||
{ 0.000619888661818225, 0.000476871323359771},
|
||||
{-0.000726760198519770, 0.000007022279302861},
|
||||
{ 0.000379089999045936, -0.000303466839685386},
|
||||
{-0.000032082305030256, 0.000136804226080666},
|
||||
{ 0.000087462353623023, 0.000188197153014303},
|
||||
{-0.000416485880859098, -0.000211750352828883},
|
||||
{ 0.000568731727879734, -0.000112347863435717},
|
||||
{-0.000345943017888307, 0.000402175417043329},
|
||||
{ 0.000015664427565742, -0.000348002612845697},
|
||||
{ 0.000054324657659007, 0.000076028700470034},
|
||||
{ 0.000154951430569292, 0.000045395998708319},
|
||||
{-0.000325534912280742, 0.000130173041693986},
|
||||
{ 0.000215876012859716, -0.000372695852521222},
|
||||
{ 0.000054431163395054, 0.000385174790951269},
|
||||
{-0.000174999505027930, -0.000168008090089447},
|
||||
{ 0.000030499908326113, 0.000003048682668941},
|
||||
{ 0.000166817395492779, -0.000105930895534485},
|
||||
{-0.000131793335799479, 0.000373003580727555},
|
||||
{-0.000169437838021966, -0.000501610900725898},
|
||||
{ 0.000488176200631435, 0.000319593757302892},
|
||||
{-0.000558465829929111, 0.000048001521408758},
|
||||
{ 0.000349316846854170, -0.000326162940234938},
|
||||
{-0.000055467806072849, 0.000356692479491629},
|
||||
{-0.000115428390169126, -0.000205816198882806},
|
||||
{ 0.000114833396071144, 0.000047778708840601},
|
||||
{-0.000038085228233508, 0.000010585909953741},
|
||||
{-0.000008324593371228, 0.000011315001355977},
|
||||
{-0.000001217597841650, -0.000039141482370942},
|
||||
{ 0.000027694034878707, 0.000033114740542633},
|
||||
{-0.000034177222729439, -0.000007245841504979},
|
||||
{ 0.000020060944485413, -0.000009851315045204},
|
||||
{-0.000005461290583903, 0.000011336784355656},
|
||||
};
|
||||
|
||||
#define CHROMA_FIR_SIZE (sizeof(CHROMA_FIR)/sizeof(dsp::complex_t))
|
||||
#define CHROMA_FIR_DELAY ((CHROMA_FIR_SIZE-1)/2)
|
131
decoder_modules/atv_decoder/src/filters.h
Normal file
131
decoder_modules/atv_decoder/src/filters.h
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
#include <dsp/types.h>
|
||||
|
||||
const dsp::complex_t CHROMA_BANDPASS[123] = {
|
||||
{ -0.000007675039564594f, -0.000017362992335168f },
|
||||
{ 0.000050180791439308f, -0.000005054021864311f },
|
||||
{ -0.000022529111707761f, 0.000102942513429095f },
|
||||
{ -0.000157609487484146f, -0.000092618697641464f },
|
||||
{ 0.000205649042029007f, -0.000181710515677257f },
|
||||
{ 0.000143445458895462f, 0.000331994546004200f },
|
||||
{ -0.000414693079508517f, 0.000038265188132615f },
|
||||
{ 0.000090081630021837f, -0.000395731646002122f },
|
||||
{ 0.000257705918065856f, 0.000154354504676150f },
|
||||
{ -0.000064051192147575f, 0.000055648228186439f },
|
||||
{ 0.000089938060647145f, 0.000213032074676941f },
|
||||
{ -0.000604775098099200f, 0.000050706635726124f },
|
||||
{ 0.000223309865890358f, -0.000944433958755193f },
|
||||
{ 0.001049943574694384f, 0.000640863688898729f },
|
||||
{ -0.000983491651119595f, 0.000840133365053179f },
|
||||
{ -0.000417178588714773f, -0.001011686459999295f },
|
||||
{ 0.000616677332283103f, -0.000046513429902547f },
|
||||
{ 0.000018549463752019f, -0.000075619948809012f },
|
||||
{ 0.000734408386201158f, 0.000456742966201638f },
|
||||
{ -0.001192460562555901f, 0.001001510577200253f },
|
||||
{ -0.000729137747758392f, -0.001811046261815935f },
|
||||
{ 0.001878272869910273f, -0.000125879189667096f },
|
||||
{ -0.000312873903977849f, 0.001230889889574772f },
|
||||
{ -0.000142534831707354f, -0.000090307321579771f },
|
||||
{ -0.000942796972567241f, 0.000778470227412111f },
|
||||
{ -0.000945381510920278f, -0.002406055808135091f },
|
||||
{ 0.003537159230775561f, -0.000207350791625892f },
|
||||
{ -0.000956199555190230f, 0.003634225577771235f },
|
||||
{ -0.002543835202533561f, -0.001641705037372486f },
|
||||
{ 0.001064108471592447f, -0.000863770138941644f },
|
||||
{ -0.000335799601479829f, -0.000876091753216939f },
|
||||
{ 0.003390761989356699f, -0.000170321604912419f },
|
||||
{ -0.001408130728751909f, 0.005175554625981795f },
|
||||
{ -0.005203055300834108f, -0.003419861284250694f },
|
||||
{ 0.004342719678657084f, -0.003465264906764298f },
|
||||
{ 0.001143432997855297f, 0.003059520699490539f },
|
||||
{ 0.000304096484476364f, -0.000012725974706621f },
|
||||
{ -0.001193870642975282f, 0.004247469277548632f },
|
||||
{ -0.006681021498855877f, -0.004471771356204969f },
|
||||
{ 0.007965721969864534f, -0.006247895626072559f },
|
||||
{ 0.003365883969059717f, 0.009241201835481184f },
|
||||
{ -0.006835562188141396f, 0.000228798228738161f },
|
||||
{ 0.000409900284971528f, -0.001412838961851673f },
|
||||
{ -0.004331406608345981f, -0.002951876085350234f },
|
||||
{ 0.009290089917766562f, -0.007161958719089258f },
|
||||
{ 0.005418326020709935f, 0.015272361365960607f },
|
||||
{ -0.017077565432843410f, 0.000428641984774326f },
|
||||
{ 0.003850771342644978f, -0.012869517593577566f },
|
||||
{ 0.004380859690202961f, 0.003039552423897447f },
|
||||
{ 0.004761181766399753f, -0.003607421240356480f },
|
||||
{ 0.005926935731028822f, 0.017160134858844222f },
|
||||
{ -0.028153584885925551f, 0.000471042980325370f },
|
||||
{ 0.009655944938035437f, -0.031314555422639050f },
|
||||
{ 0.023930146568136038f, 0.016901617811072800f },
|
||||
{ -0.012998853255109976f, 0.009678807314399702f },
|
||||
{ 0.002043176559434885f, 0.006079907699564680f },
|
||||
{ -0.036686455817128191f, 0.000306882557812233f },
|
||||
{ 0.021529138474771701f, -0.067800343150283604f },
|
||||
{ 0.085421344938160879f, 0.061409588050754214f },
|
||||
{ -0.108166660998898100f, 0.079141989828113088f },
|
||||
{ -0.047617308971534079f, -0.145721049254261960f },
|
||||
{ 0.160079041453427080f, -0.000000000000000427f },
|
||||
{ -0.047617308971533295f, 0.145721049254262240f },
|
||||
{ -0.108166660998898530f, -0.079141989828112505f },
|
||||
{ 0.085421344938160546f, -0.061409588050754672f },
|
||||
{ 0.021529138474772065f, 0.067800343150283493f },
|
||||
{ -0.036686455817128191f, -0.000306882557812037f },
|
||||
{ 0.002043176559434853f, -0.006079907699564691f },
|
||||
{ -0.012998853255110026f, -0.009678807314399631f },
|
||||
{ 0.023930146568135951f, -0.016901617811072928f },
|
||||
{ 0.009655944938035604f, 0.031314555422638994f },
|
||||
{ -0.028153584885925554f, -0.000471042980325220f },
|
||||
{ 0.005926935731028730f, -0.017160134858844253f },
|
||||
{ 0.004761181766399772f, 0.003607421240356455f },
|
||||
{ 0.004380859690202943f, -0.003039552423897470f },
|
||||
{ 0.003850771342645046f, 0.012869517593577545f },
|
||||
{ -0.017077565432843413f, -0.000428641984774235f },
|
||||
{ 0.005418326020709854f, -0.015272361365960637f },
|
||||
{ 0.009290089917766600f, 0.007161958719089209f },
|
||||
{ -0.004331406608345964f, 0.002951876085350257f },
|
||||
{ 0.000409900284971536f, 0.001412838961851670f },
|
||||
{ -0.006835562188141398f, -0.000228798228738125f },
|
||||
{ 0.003365883969059667f, -0.009241201835481201f },
|
||||
{ 0.007965721969864567f, 0.006247895626072517f },
|
||||
{ -0.006681021498855855f, 0.004471771356205005f },
|
||||
{ -0.001193870642975304f, -0.004247469277548626f },
|
||||
{ 0.000304096484476364f, 0.000012725974706619f },
|
||||
{ 0.001143432997855281f, -0.003059520699490545f },
|
||||
{ 0.004342719678657102f, 0.003465264906764274f },
|
||||
{ -0.005203055300834089f, 0.003419861284250722f },
|
||||
{ -0.001408130728751936f, -0.005175554625981787f },
|
||||
{ 0.003390761989356700f, 0.000170321604912401f },
|
||||
{ -0.000335799601479825f, 0.000876091753216940f },
|
||||
{ 0.001064108471592452f, 0.000863770138941638f },
|
||||
{ -0.002543835202533552f, 0.001641705037372499f },
|
||||
{ -0.000956199555190250f, -0.003634225577771230f },
|
||||
{ 0.003537159230775563f, 0.000207350791625874f },
|
||||
{ -0.000945381510920265f, 0.002406055808135096f },
|
||||
{ -0.000942796972567245f, -0.000778470227412106f },
|
||||
{ -0.000142534831707354f, 0.000090307321579771f },
|
||||
{ -0.000312873903977856f, -0.001230889889574770f },
|
||||
{ 0.001878272869910274f, 0.000125879189667086f },
|
||||
{ -0.000729137747758382f, 0.001811046261815939f },
|
||||
{ -0.001192460562555906f, -0.001001510577200246f },
|
||||
{ 0.000734408386201156f, -0.000456742966201642f },
|
||||
{ 0.000018549463752019f, 0.000075619948809012f },
|
||||
{ 0.000616677332283103f, 0.000046513429902543f },
|
||||
{ -0.000417178588714767f, 0.001011686459999298f },
|
||||
{ -0.000983491651119600f, -0.000840133365053174f },
|
||||
{ 0.001049943574694380f, -0.000640863688898734f },
|
||||
{ 0.000223309865890363f, 0.000944433958755192f },
|
||||
{ -0.000604775098099200f, -0.000050706635726121f },
|
||||
{ 0.000089938060647144f, -0.000213032074676941f },
|
||||
{ -0.000064051192147576f, -0.000055648228186438f },
|
||||
{ 0.000257705918065856f, -0.000154354504676151f },
|
||||
{ 0.000090081630021839f, 0.000395731646002121f },
|
||||
{ -0.000414693079508517f, -0.000038265188132613f },
|
||||
{ 0.000143445458895461f, -0.000331994546004200f },
|
||||
{ 0.000205649042029008f, 0.000181710515677256f },
|
||||
{ -0.000157609487484145f, 0.000092618697641465f },
|
||||
{ -0.000022529111707761f, -0.000102942513429094f },
|
||||
{ 0.000050180791439308f, 0.000005054021864311f },
|
||||
{ -0.000007675039564594f, 0.000017362992335168f }
|
||||
};
|
||||
|
||||
#define CHROMA_BANDPASS_SIZE (sizeof(CHROMA_BANDPASS)/sizeof(dsp::complex_t))
|
||||
#define CHROMA_BANDPASS_DELAY (CHROMA_BANDPASS_SIZE/2)
|
@ -22,8 +22,16 @@
|
||||
|
||||
#define SYNC_LEVEL (-0.428)
|
||||
|
||||
#define COLORBURST_START 84
|
||||
#define COLORBURST_LEN 33
|
||||
|
||||
#define MAX_LOCK 1000
|
||||
|
||||
dsp::complex_t PHASE_REF[2] = {
|
||||
{ -0.707106781186547f, 0.707106781186547f },
|
||||
{ -0.707106781186547f, -0.707106781186547f }
|
||||
};
|
||||
|
||||
class LineSync : public dsp::Processor<float, float> {
|
||||
using base_type = dsp::Processor<float, float>;
|
||||
public:
|
||||
|
@ -16,15 +16,14 @@
|
||||
#include <dsp/filter/fir.h>
|
||||
#include <dsp/taps/from_array.h>
|
||||
|
||||
#include "chrominance_filter.h"
|
||||
|
||||
#include "chroma_pll.h"
|
||||
|
||||
#include "linesync_old.h"
|
||||
#include "amplitude.h"
|
||||
#include <dsp/demod/am.h>
|
||||
#include <dsp/loop/fast_agc.h>
|
||||
|
||||
#include "filters.h"
|
||||
#include <dsp/math/normalize_phase.h>
|
||||
#include <fstream>
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
|
||||
SDRPP_MOD_INFO{/* Name: */ "atv_decoder",
|
||||
@ -51,6 +50,8 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
|
||||
r2c.init(NULL);
|
||||
|
||||
file = std::ofstream("chromasub_diff.bin", std::ios::binary | std::ios::out);
|
||||
|
||||
agc.start();
|
||||
demod.start();
|
||||
sync.start();
|
||||
@ -82,6 +83,8 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
|
||||
std::ofstream file;
|
||||
|
||||
private:
|
||||
static void menuHandler(void *ctx) {
|
||||
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
|
||||
@ -118,10 +121,17 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
style::endDisabled();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Close Debug")) {
|
||||
_this->file.close();
|
||||
}
|
||||
|
||||
ImGui::Text("Gain: %f", _this->gain);
|
||||
ImGui::Text("Offset: %f", _this->offset);
|
||||
ImGui::Text("Subcarrier: %f", _this->subcarrierFreq);
|
||||
}
|
||||
|
||||
uint32_t pp = 0;
|
||||
|
||||
static void handler(float *data, int count, void *ctx) {
|
||||
ATVDecoderModule *_this = (ATVDecoderModule *)ctx;
|
||||
|
||||
@ -158,14 +168,71 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
// Save sync type to history
|
||||
_this->syncHistory = (_this->syncHistory << 2) | (longSync << 1) | shortSync;
|
||||
|
||||
// If the line has a colorburst, decode it
|
||||
dsp::complex_t* buf1 = _this->r2c.out.readBuf;
|
||||
dsp::complex_t* buf2 = _this->r2c.out.writeBuf;
|
||||
if (true) {
|
||||
// Convert the line into complex
|
||||
_this->r2c.process(count, data, buf1);
|
||||
|
||||
// Extract the chroma subcarrier (TODO: Optimise by running only where needed)
|
||||
for (int i = COLORBURST_START; i < count-(CHROMA_BANDPASS_DELAY+1); i++) {
|
||||
volk_32fc_x2_dot_prod_32fc((lv_32fc_t*)&buf2[i], (lv_32fc_t*)&buf1[i - CHROMA_BANDPASS_DELAY], (lv_32fc_t*)CHROMA_BANDPASS, CHROMA_BANDPASS_SIZE);
|
||||
}
|
||||
|
||||
// Down convert the chroma subcarrier (TODO: Optimise by running only where needed)
|
||||
lv_32fc_t startPhase = { 1.0f, 0.0f };
|
||||
lv_32fc_t phaseDelta = { sinf(_this->subcarrierFreq), cosf(_this->subcarrierFreq) };
|
||||
#if VOLK_VERSION >= 030100
|
||||
volk_32fc_s32fc_x2_rotator2_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], &phaseDelta, &startPhase, count - COLORBURST_START);
|
||||
#else
|
||||
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], phaseDelta, &startPhase, count - COLORBURST_START);
|
||||
#endif
|
||||
|
||||
// Compute the phase of the burst
|
||||
dsp::complex_t burstAvg = { 0.0f, 0.0f };
|
||||
volk_32fc_accumulator_s32fc((lv_32fc_t*)&burstAvg, (lv_32fc_t*)&buf2[COLORBURST_START], COLORBURST_LEN);
|
||||
float burstAmp = burstAvg.amplitude();
|
||||
if (burstAmp*(1.0f/(float)COLORBURST_LEN) < 0.02f) {
|
||||
printf("%d\n", _this->line);
|
||||
}
|
||||
burstAvg *= (1.0f / (burstAmp*burstAmp));
|
||||
burstAvg = burstAvg.conj();
|
||||
|
||||
// Normalize the chroma data (TODO: Optimise by running only where needed)
|
||||
volk_32fc_s32fc_multiply_32fc((lv_32fc_t*)&buf2[COLORBURST_START], (lv_32fc_t*)&buf2[COLORBURST_START], *((lv_32fc_t*)&burstAvg), count - COLORBURST_START);
|
||||
|
||||
// Compute the frequency error of the burst
|
||||
float phase = buf2[COLORBURST_START].phase();
|
||||
float error = 0.0f;
|
||||
for (int i = COLORBURST_START+1; i < COLORBURST_START+COLORBURST_LEN; i++) {
|
||||
float cphase = buf2[i].phase();
|
||||
error += dsp::math::normalizePhase(cphase - phase);
|
||||
phase = cphase;
|
||||
}
|
||||
error *= (1.0f / (float)(COLORBURST_LEN-1));
|
||||
|
||||
// Update the subcarrier freq
|
||||
_this->subcarrierFreq += error*0.0001f;
|
||||
}
|
||||
|
||||
// Render the line if it's visible
|
||||
if (_this->ypos >= 34 && _this->ypos <= 34+576-1) {
|
||||
uint32_t* currentLine = &((uint32_t *)_this->img.buffer)[(_this->ypos - 34)*768];
|
||||
if (_this->colorMode) {
|
||||
for (int i = 155; i < (155+768); i++) {
|
||||
int imval = std::clamp<float>(data[i] * 255.0f, 0, 255);
|
||||
int imval1 = std::clamp<float>(fabsf(buf2[i-155+COLORBURST_START].re*5.0f) * 255.0f, 0, 255);
|
||||
int imval2 = std::clamp<float>(fabsf(buf2[i-155+COLORBURST_START].im*5.0f) * 255.0f, 0, 255);
|
||||
currentLine[i-155] = 0xFF000000 | (imval2 << 8) | imval1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 155; i < (155+768); i++) {
|
||||
int imval = std::clamp<float>(data[i-155+COLORBURST_START] * 255.0f, 0, 255);
|
||||
currentLine[i-155] = 0xFF000000 | (imval << 16) | (imval << 8) | imval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute whether to rollover
|
||||
bool rollToOdd = (_this->ypos == 624);
|
||||
@ -188,6 +255,7 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
|
||||
// Start the odd field
|
||||
_this->ypos = 1;
|
||||
_this->line++;
|
||||
}
|
||||
else if (rollToEven || syncToEven) {
|
||||
// Update the vertical lock state
|
||||
@ -201,12 +269,14 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
|
||||
// Start the even field
|
||||
_this->ypos = 0;
|
||||
_this->line = 0;
|
||||
|
||||
// Swap the video buffer
|
||||
_this->img.swap();
|
||||
}
|
||||
else {
|
||||
_this->ypos += 2;
|
||||
_this->line++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,8 +284,10 @@ class ATVDecoderModule : public ModuleManager::Instance {
|
||||
float offset = 0.0f;
|
||||
float gain = 1.0f;
|
||||
uint16_t syncHistory = 0;
|
||||
int line = 0;
|
||||
int ypos = 0;
|
||||
int vlock = 0;
|
||||
float subcarrierFreq = 0.0f;
|
||||
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <gui/style.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <chrono>
|
||||
|
||||
SDRPP_MOD_INFO{
|
||||
/* Name: */ "scanner",
|
||||
|
9
source_modules/sddc_source/CMakeLists.txt
Normal file
9
source_modules/sddc_source/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sddc_source)
|
||||
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
|
||||
include(${SDRPP_MODULE_CMAKE})
|
||||
|
||||
add_subdirectory("./libsddc")
|
||||
target_link_libraries(sddc_source PRIVATE sddc)
|
2
source_modules/sddc_source/libsddc/.gitignore
vendored
Normal file
2
source_modules/sddc_source/libsddc/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build/
|
||||
.vscode/
|
87
source_modules/sddc_source/libsddc/CMakeLists.txt
Normal file
87
source_modules/sddc_source/libsddc/CMakeLists.txt
Normal file
@ -0,0 +1,87 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(libsddc VERSION 0.2.0)
|
||||
|
||||
# Options
|
||||
option(BUILD_SDDC_UTILS "Build SDDC utilities such as sddc_info" ON)
|
||||
option(INSTALL_UDEV_RULES "Install UDEV rules (Linux only)" ON)
|
||||
|
||||
# List all source files
|
||||
file(GLOB_RECURSE SRC "src/*.c")
|
||||
|
||||
# On windows, all symbols must be exported
|
||||
if (MSVC)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif ()
|
||||
|
||||
# Create dynamic libs
|
||||
add_library(sddc SHARED ${SRC})
|
||||
|
||||
# # Set optimisation flags
|
||||
# if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
# # Debug Flags
|
||||
# if (MSVC)
|
||||
# target_compile_options(sddc PRIVATE /EHsc)
|
||||
# else ()
|
||||
# target_compile_options(sddc PRIVATE -g -Og)
|
||||
# endif ()
|
||||
# else()
|
||||
# # Normal Flags
|
||||
# if (MSVC)
|
||||
# target_compile_options(sddc PRIVATE /O2 /Ob2 /EHsc)
|
||||
# else ()
|
||||
# target_compile_options(sddc PRIVATE -O3)
|
||||
# endif ()
|
||||
# endif()
|
||||
|
||||
# Include the include folder
|
||||
target_include_directories(sddc PUBLIC "include/")
|
||||
|
||||
# Find libusb
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)
|
||||
|
||||
# Link to libusb
|
||||
target_link_libraries(sddc PRIVATE PkgConfig::libusb)
|
||||
|
||||
# TODO: Have it default instead of override
|
||||
if (MSVC)
|
||||
set(CMAKE_INSTALL_PREFIX "C:/Program Files/SDDC/")
|
||||
set(CMAKE_INSTALL_BINDIR "bin")
|
||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include")
|
||||
else ()
|
||||
include(GNUInstallDirs)
|
||||
endif ()
|
||||
|
||||
if (NOT MSVC)
|
||||
# Configure pkgconfig file
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libsddc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libsddc.pc @ONLY)
|
||||
|
||||
# Install pkgconfig file
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libsddc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
endif ()
|
||||
|
||||
# Install the library
|
||||
if (MSVC)
|
||||
install(TARGETS sddc)
|
||||
else ()
|
||||
install(TARGETS sddc DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif ()
|
||||
|
||||
# Install the headers
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# On Windows, install dependencies
|
||||
if (MSVC)
|
||||
install(FILES $<TARGET_FILE_DIR:sddc>/libusb-1.0.dll DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif ()
|
||||
|
||||
# Build utils if enabled
|
||||
if (BUILD_SDDC_UTILS)
|
||||
add_subdirectory("utils/sddc_info")
|
||||
add_subdirectory("utils/sddc_rx")
|
||||
endif ()
|
||||
|
||||
# # Create uninstall target
|
||||
# configure_file(${CMAKE_SOURCE_DIR}/cmake/uninstall.cmake ${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake @ONLY)
|
||||
# add_custom_target(uninstall ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/uninstall.cmake)
|
32
source_modules/sddc_source/libsddc/cmake/uninstall.cmake
Normal file
32
source_modules/sddc_source/libsddc/cmake/uninstall.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
|
||||
|
||||
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
STRING(REGEX REPLACE "\n" ";" files "${files}")
|
||||
FOREACH(file ${files})
|
||||
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
IF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSE(EXISTS "$ENV{DESTDIR}${file}")
|
||||
MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
ENDIF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
ENDFOREACH(file)
|
177
source_modules/sddc_source/libsddc/include/sddc.h
Normal file
177
source_modules/sddc_source/libsddc/include/sddc.h
Normal file
@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Handle inclusion from C++ code
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SDDC_SERIAL_MAX_LEN 256
|
||||
|
||||
enum sddc_model {
|
||||
SDDC_MODEL_UNKNOWN = 0x00,
|
||||
SDDC_MODEL_BBRF103 = 0x01,
|
||||
SDDC_MODEL_HF103 = 0x02,
|
||||
SDDC_MODEL_RX888 = 0x03,
|
||||
SDDC_MODEL_RX888_MK2 = 0x04,
|
||||
SDDC_MODEL_RX999 = 0x05,
|
||||
SDDC_MODEL_RXLUCY = 0x06,
|
||||
SDDC_MODEL_RX888_MK3 = 0x07
|
||||
};
|
||||
typedef enum sddc_model sddc_model_t;
|
||||
|
||||
enum sddc_error {
|
||||
SDDC_ERROR_UNKNOWN = -99,
|
||||
SDDC_ERROR_NOT_IMPLEMENTED = -98,
|
||||
|
||||
SDDC_ERROR_FIRMWARE_UPLOAD_FAILED = -4,
|
||||
SDDC_ERROR_NOT_FOUND = -3,
|
||||
SDDC_ERROR_USB_ERROR = -2,
|
||||
SDDC_ERROR_TIMEOUT = -1,
|
||||
|
||||
SDDC_SUCCESS = 0
|
||||
};
|
||||
typedef enum sddc_error sddc_error_t;
|
||||
|
||||
/**
|
||||
* Device instance.
|
||||
*/
|
||||
struct sddc_dev;
|
||||
typedef struct sddc_dev sddc_dev_t;
|
||||
|
||||
/**
|
||||
* Device information.
|
||||
*/
|
||||
struct sddc_devinfo {
|
||||
const char serial[SDDC_SERIAL_MAX_LEN];
|
||||
sddc_model_t model;
|
||||
int firmwareMajor;
|
||||
int firmwareMinor;
|
||||
};
|
||||
typedef struct sddc_devinfo sddc_devinfo_t;
|
||||
|
||||
/**
|
||||
* Parameter range. A step size of zero means infinitely variable.
|
||||
*/
|
||||
struct sddc_range {
|
||||
double start;
|
||||
double end;
|
||||
double step;
|
||||
};
|
||||
typedef struct sddc_range sddc_range_t;
|
||||
|
||||
/**
|
||||
* Get the string representation of a device model.
|
||||
* @param model Model to get the string representation of.
|
||||
* @return String representation of the model.
|
||||
*/
|
||||
const char* sddc_model_to_string(sddc_model_t model);
|
||||
|
||||
/**
|
||||
* Get the string representation of an error.
|
||||
* @param model Error to get the string representation of.
|
||||
* @return String representation of the error.
|
||||
*/
|
||||
const char* sddc_error_to_string(sddc_error_t error);
|
||||
|
||||
/**
|
||||
* Set the path to the firmware image.
|
||||
* @param path Path to the firmware image.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_set_firmware_path(const char* path);
|
||||
|
||||
/**
|
||||
* Get a list of connected devices. The returned list has to be freed using `sddc_free_device_list()` if it isn't empty.
|
||||
* @param dev_list Pointer to a list of devices.
|
||||
* @return Number of devices in the list or an error code if an error occured.
|
||||
*/
|
||||
int sddc_get_device_list(sddc_devinfo_t** dev_list);
|
||||
|
||||
/**
|
||||
* Free a device list returned by `sddc_get_device_list()`. Attempting to free a list returned empty has no effect.
|
||||
* @param dev_list Device list to free.
|
||||
*/
|
||||
void sddc_free_device_list(sddc_devinfo_t* dev_list);
|
||||
|
||||
/**
|
||||
* Open a device by its serial number.
|
||||
* @param serial Serial number of the device to open.
|
||||
* @param dev Pointer to a SDDC device pointer to populate once open.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_open(const char* serial, sddc_dev_t** dev);
|
||||
|
||||
/**
|
||||
* Close an opened SDDC device.
|
||||
* @param dev SDDC Device to close.
|
||||
*/
|
||||
void sddc_close(sddc_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Get the range of samplerate supported by a device.
|
||||
* @param dev SDDC device.
|
||||
* @return Range of supported samplerates.
|
||||
*/
|
||||
sddc_range_t sddc_get_samplerate_range(sddc_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set the device's sampling rate.
|
||||
* @param dev SDDC device.
|
||||
* @param samplerate Sampling rate.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_set_samplerate(sddc_dev_t* dev, uint32_t samplerate);
|
||||
|
||||
/**
|
||||
* Enable the ADC's dithering feature.
|
||||
* @param dev SDDC device.
|
||||
* @param enabled True to enable dithering, false to disable it.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_set_dithering(sddc_dev_t* dev, bool enabled);
|
||||
|
||||
/**
|
||||
* Enable the ADC's randomizer feature.
|
||||
* @param dev SDDC device.
|
||||
* @param enabled True to enable randomization, false to disable it.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_set_randomizer(sddc_dev_t* dev, bool enabled);
|
||||
|
||||
/**
|
||||
* Set the LO of the tuner.
|
||||
* @param dev SDDC device.
|
||||
* @param frequency Frequency of the LO.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_set_tuner_frequency(sddc_dev_t* dev, uint64_t frequency);
|
||||
|
||||
/**
|
||||
* Start the device.
|
||||
* @param dev SDDC device.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_start(sddc_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Stop the device.
|
||||
* @param dev SDDC device.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_stop(sddc_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Receive samples.
|
||||
* @param dev SDDC device.
|
||||
* @param samples Buffer to write the samples to.
|
||||
* @param count Number of samples to read.
|
||||
* @return SDDC_SUCCESS on success or an error code otherwise.
|
||||
*/
|
||||
sddc_error_t sddc_rx(sddc_dev_t* dev, int16_t* samples, int count);
|
||||
|
||||
// Handle inclusion from C++ code
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
165
source_modules/sddc_source/libsddc/license
Normal file
165
source_modules/sddc_source/libsddc/license
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
116
source_modules/sddc_source/libsddc/src/fx3_boot.c
Normal file
116
source_modules/sddc_source/libsddc/src/fx3_boot.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "fx3_boot.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define FX3_TIMEOUT 1000
|
||||
#define FX3_VENDOR_REQUEST 0xA0
|
||||
#define FX3_MAX_BLOCK_SIZE 0x1000
|
||||
|
||||
int sddc_fx3_boot_mem_read(libusb_device_handle* dev, uint32_t addr, uint8_t* data, uint16_t len) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, addr & 0xFFFF, addr >> 16, data, len, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_mem_write(libusb_device_handle* dev, uint32_t addr, const uint8_t* data, uint16_t len) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, addr & 0xFFFF, addr >> 16, data, len, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_run(libusb_device_handle* dev, uint32_t entry) {
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, FX3_VENDOR_REQUEST, entry & 0xFFFF, entry >> 16, NULL, 0, FX3_TIMEOUT);
|
||||
}
|
||||
|
||||
int sddc_fx3_boot_upload_firmware(libusb_device_handle* dev, const char* path) {
|
||||
// Open the firmware image
|
||||
FILE* fw = fopen(path, "rb");
|
||||
if (!fw) {
|
||||
fprintf(stderr, "Failed to open firmware image\n");
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Read the signature
|
||||
char sign[2];
|
||||
int read = fread(sign, 2, 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Failed to read firmware image signature: %d\n", read);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Check the signature
|
||||
if (sign[0] != 'C' || sign[1] != 'Y') {
|
||||
fprintf(stderr, "Firmware image has invalid signature\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Skip useless metadata
|
||||
int err = fseek(fw, 2, SEEK_CUR);
|
||||
if (err) {
|
||||
fprintf(stderr, "Invalid firmware image: %d\n", err);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Preallocate data buffer
|
||||
int bufferSize = 0x10000;
|
||||
uint8_t* buffer = malloc(bufferSize);
|
||||
|
||||
// Read every section
|
||||
while (1) {
|
||||
// Read the section size
|
||||
uint32_t sizeWords;
|
||||
read = fread(&sizeWords, sizeof(uint32_t), 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Invalid firmware image section size\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
uint32_t size = sizeWords << 2;
|
||||
|
||||
// Read the section address
|
||||
uint32_t addr;
|
||||
read = fread(&addr, sizeof(uint32_t), 1, fw);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Invalid firmware image section address\n");
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// If the section is a termination section, run the code at the given address
|
||||
if (!size) {
|
||||
sddc_fx3_boot_run(dev, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
// Re-allocate buffer if needed
|
||||
if (size > bufferSize) {
|
||||
bufferSize = size;
|
||||
realloc(buffer, bufferSize);
|
||||
}
|
||||
|
||||
// Read the section data
|
||||
read = fread(buffer, 1, size, fw);
|
||||
if (read != size) {
|
||||
fprintf(stderr, "Failed to read section data: %d\n", read);
|
||||
fclose(fw);
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Upload it to the chip
|
||||
for (int i = 0; i < size; i += FX3_MAX_BLOCK_SIZE) {
|
||||
int left = size - i;
|
||||
err = sddc_fx3_boot_mem_write(dev, addr + i, &buffer[i], (left > FX3_MAX_BLOCK_SIZE) ? FX3_MAX_BLOCK_SIZE : left);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to write to device memory: %d\n", err);
|
||||
fclose(fw);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Checksum stuff and verification ideally
|
||||
|
||||
// Close the firmware image
|
||||
fclose(fw);
|
||||
|
||||
// Return successfully
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
39
source_modules/sddc_source/libsddc/src/fx3_boot.h
Normal file
39
source_modules/sddc_source/libsddc/src/fx3_boot.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <libusb.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Read data from the device's memory.
|
||||
* @param dev Device to read data from.
|
||||
* @param addr Start address of the data in the device's memory.
|
||||
* @param data Buffer to write the data into.
|
||||
* @param len Number of bytes to read.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_mem_read(libusb_device_handle* dev, uint32_t addr, uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Write data to the device's memory.
|
||||
* @param dev Device to write data to.
|
||||
* @param addr Start address of the data in the device's memory.
|
||||
* @param data Buffer to write the data into.
|
||||
* @param len Number of bytes to read.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_mem_write(libusb_device_handle* dev, uint32_t addr, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Execute code on the device.
|
||||
* @param dev Device to execute code on.
|
||||
* @param entry Entry point of the code.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_run(libusb_device_handle* dev, uint32_t entry);
|
||||
|
||||
/**
|
||||
* Parse, upload and execute a firmware image.
|
||||
* @param dev Device to upload the firmware to.
|
||||
* @param path Path to the firmware image.
|
||||
* @return libusb error code.
|
||||
*/
|
||||
int sddc_fx3_boot_upload_firmware(libusb_device_handle* dev, const char* path);
|
451
source_modules/sddc_source/libsddc/src/sddc.c
Normal file
451
source_modules/sddc_source/libsddc/src/sddc.c
Normal file
@ -0,0 +1,451 @@
|
||||
#include <sddc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <libusb.h>
|
||||
#include <stdio.h>
|
||||
#include "usb_interface.h"
|
||||
|
||||
struct sddc_dev {
|
||||
// USB handles
|
||||
struct libusb_device_handle* openDev;
|
||||
|
||||
// Device info
|
||||
sddc_devinfo_t info;
|
||||
|
||||
// Device state
|
||||
bool running;
|
||||
uint32_t samplerate;
|
||||
uint64_t tunerFreq;
|
||||
sddc_gpio_t gpioState;
|
||||
};
|
||||
|
||||
struct libusb_context* ctx = NULL;
|
||||
char* sddc_firmware_path = NULL;
|
||||
bool sddc_is_init = false;
|
||||
|
||||
void sddc_init() {
|
||||
// If already initialized, do nothing
|
||||
if (sddc_is_init) { return; }
|
||||
|
||||
// If the firmware isn't already found, find it
|
||||
if (!sddc_firmware_path) {
|
||||
// TODO: Find the firmware
|
||||
}
|
||||
|
||||
// Init libusb
|
||||
libusb_init(&ctx);
|
||||
}
|
||||
|
||||
const char* sddc_model_to_string(sddc_model_t model) {
|
||||
switch (model) {
|
||||
case SDDC_MODEL_BBRF103: return "BBRF103";
|
||||
case SDDC_MODEL_HF103: return "HF103";
|
||||
case SDDC_MODEL_RX888: return "RX888";
|
||||
case SDDC_MODEL_RX888_MK2: return "RX888 MK2";
|
||||
case SDDC_MODEL_RX999: return "RX999";
|
||||
case SDDC_MODEL_RXLUCY: return "RXLUCY";
|
||||
case SDDC_MODEL_RX888_MK3: return "RX888 MK3";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char* sddc_error_to_string(sddc_error_t error) {
|
||||
switch (error) {
|
||||
case SDDC_ERROR_NOT_IMPLEMENTED: return "Not Implemented";
|
||||
case SDDC_ERROR_FIRMWARE_UPLOAD_FAILED: return "Firmware Upload Failed";
|
||||
case SDDC_ERROR_NOT_FOUND: return "Not Found";
|
||||
case SDDC_ERROR_USB_ERROR: return "USB Error";
|
||||
case SDDC_ERROR_TIMEOUT: return "Timeout";
|
||||
case SDDC_SUCCESS: return "Success";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_firmware_path(const char* path) {
|
||||
// Free the old path if it exists
|
||||
if (sddc_firmware_path) { free(sddc_firmware_path); }
|
||||
|
||||
// Allocate the new path
|
||||
sddc_firmware_path = malloc(strlen(path) + 1);
|
||||
|
||||
// Copy the new path
|
||||
strcpy(sddc_firmware_path, path);
|
||||
|
||||
// TODO: Check if the file path exists
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
int sddc_get_device_list(sddc_devinfo_t** dev_list) {
|
||||
// Initialize libsddc in case it isn't already
|
||||
sddc_init();
|
||||
|
||||
// Get a list of USB devices
|
||||
libusb_device** devices;
|
||||
int devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Initialize all uninitialized devices
|
||||
bool uninit = false;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If it's not an uninitialized device, go to next device
|
||||
if (desc.idVendor != SDDC_UNINIT_VID || desc.idProduct != SDDC_UNINIT_PID) { continue; }
|
||||
|
||||
// Initialize the device
|
||||
printf("Found uninitialized device, initializing...\n");
|
||||
// TODO: Check that the firmware path is valid
|
||||
sddc_error_t serr = sddc_init_device(dev, sddc_firmware_path);
|
||||
if (serr != SDDC_SUCCESS) { continue; }
|
||||
|
||||
// Set the flag to wait the devices to start up
|
||||
uninit = true;
|
||||
}
|
||||
|
||||
// If some uninitialized devices were found
|
||||
if (uninit) {
|
||||
// Free the device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Wait for the devices to show back up
|
||||
#ifdef _WIN32
|
||||
Sleep(SDDC_INIT_SEARCH_DELAY_MS);
|
||||
#else
|
||||
usleep(SDDC_INIT_SEARCH_DELAY_MS * 1000);
|
||||
#endif
|
||||
|
||||
// Attempt to list devices again
|
||||
devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Allocate the device list
|
||||
*dev_list = malloc(devCount * sizeof(sddc_devinfo_t));
|
||||
|
||||
// Check each device
|
||||
int found = 0;
|
||||
libusb_device_handle* openDev;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If the device is not an SDDC device, go to next device
|
||||
if (desc.idVendor != SDDC_VID || desc.idProduct != SDDC_PID) { continue; }
|
||||
|
||||
// Open the device
|
||||
err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open device: %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create entry
|
||||
sddc_devinfo_t* info = &((*dev_list)[found]);
|
||||
|
||||
// Get the serial number
|
||||
err = libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, info->serial, SDDC_SERIAL_MAX_LEN-1);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get descriptor: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the hardware info
|
||||
sddc_hwinfo_t hwinfo;
|
||||
err = sddc_fx3_get_info(openDev, &hwinfo, 0);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get device info: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the hardware info
|
||||
info->model = (sddc_model_t)hwinfo.model;
|
||||
info->firmwareMajor = hwinfo.firmwareConfigH;
|
||||
info->firmwareMinor = hwinfo.firmwareConfigL;
|
||||
|
||||
// Close the device
|
||||
libusb_close(openDev);
|
||||
|
||||
// Increment device counter
|
||||
found++;
|
||||
}
|
||||
|
||||
// Free the libusb device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Return the number of devices found
|
||||
return found;
|
||||
}
|
||||
|
||||
void sddc_free_device_list(sddc_devinfo_t* dev_list) {
|
||||
// Free the device list if it exists
|
||||
if (dev_list) { free(dev_list); };
|
||||
}
|
||||
|
||||
sddc_error_t sddc_open(const char* serial, sddc_dev_t** dev) {
|
||||
// Initialize libsddc in case it isn't already
|
||||
sddc_init();
|
||||
|
||||
// Get a list of USB devices
|
||||
libusb_device** devices;
|
||||
int devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Initialize all uninitialized devices
|
||||
bool uninit = false;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If it's not an uninitialized device, go to next device
|
||||
if (desc.idVendor != SDDC_UNINIT_VID || desc.idProduct != SDDC_UNINIT_PID) { continue; }
|
||||
|
||||
// Initialize the device
|
||||
printf("Found uninitialized device, initializing...\n");
|
||||
// TODO: Check that the firmware path is valid
|
||||
sddc_error_t serr = sddc_init_device(dev, sddc_firmware_path);
|
||||
if (serr != SDDC_SUCCESS) { continue; }
|
||||
|
||||
// Set the flag to wait the devices to start up
|
||||
uninit = true;
|
||||
}
|
||||
|
||||
// If some uninitialized devices were found
|
||||
if (uninit) {
|
||||
// Free the device list
|
||||
libusb_free_device_list(devices, 1);
|
||||
|
||||
// Wait for the devices to show back up
|
||||
#ifdef _WIN32
|
||||
Sleep(SDDC_INIT_SEARCH_DELAY_MS);
|
||||
#else
|
||||
usleep(SDDC_INIT_SEARCH_DELAY_MS * 1000);
|
||||
#endif
|
||||
|
||||
// Attempt to list devices again
|
||||
devCount = libusb_get_device_list(ctx, &devices);
|
||||
if (devCount < 0 || !devices) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Search through all USB device
|
||||
bool found = false;
|
||||
libusb_device_handle* openDev;
|
||||
for (int i = 0; i < devCount; i++) {
|
||||
// Get the device from the list
|
||||
libusb_device* dev = devices[i];
|
||||
|
||||
// Get the device descriptor. Fail silently on error as it might not even be a SDDC device.
|
||||
struct libusb_device_descriptor desc;
|
||||
int err = libusb_get_device_descriptor(dev, &desc);
|
||||
if (err != LIBUSB_SUCCESS) { continue; }
|
||||
|
||||
// If the device is not an SDDC device, go to next device
|
||||
if (desc.idVendor != SDDC_VID || desc.idProduct != SDDC_PID) { continue; }
|
||||
|
||||
// Open the device
|
||||
err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
fprintf(stderr, "Failed to open device: %d\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the serial number
|
||||
char dserial[SDDC_SERIAL_MAX_LEN];
|
||||
err = libusb_get_string_descriptor_ascii(openDev, desc.iSerialNumber, dserial, SDDC_SERIAL_MAX_LEN-1);
|
||||
if (err < LIBUSB_SUCCESS) {
|
||||
printf("Failed to get descriptor: %d\n", err);
|
||||
libusb_close(openDev);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare the serial number and give up if not a match
|
||||
if (strcmp(dserial, serial)) { continue; }
|
||||
|
||||
// Get the device info
|
||||
// TODO
|
||||
|
||||
// Set the found flag and stop searching
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Free the libusb device list
|
||||
libusb_free_device_list(devices, true);
|
||||
|
||||
// If the device was not found, give up
|
||||
if (!found) { return SDDC_ERROR_NOT_FOUND; }
|
||||
|
||||
// Claim the interface
|
||||
libusb_claim_interface(openDev, 0);
|
||||
|
||||
// Allocate the device object
|
||||
*dev = malloc(sizeof(sddc_dev_t));
|
||||
|
||||
// Initialize the device object
|
||||
(*dev)->openDev = openDev;
|
||||
//(*dev)->info = ; //TODO
|
||||
(*dev)->running = false;
|
||||
(*dev)->samplerate = 128e6;
|
||||
(*dev)->tunerFreq = 100e6;
|
||||
(*dev)->gpioState = SDDC_GPIO_SHUTDOWN | SDDC_GPIO_SEL0; // ADC shutdown and HF port selected
|
||||
|
||||
// Stop everything in case the device is partially started
|
||||
printf("Stopping...\n");
|
||||
sddc_stop(*dev);
|
||||
|
||||
// TODO: Setup all of the other state
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_SEL0, false);
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_SEL1, true);
|
||||
sddc_gpio_put(*dev, SDDC_GPIO_VHF_EN, true);
|
||||
sddc_tuner_start((*dev)->openDev, 16e6);
|
||||
sddc_tuner_tune((*dev)->openDev, 100e6);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_R82XX_ATT, 15);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_R83XX_VGA, 9);
|
||||
sddc_fx3_set_param((*dev)->openDev, SDDC_PARAM_AD8340_VGA, 5);
|
||||
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
void sddc_close(sddc_dev_t* dev) {
|
||||
// Stop everything
|
||||
sddc_stop(dev);
|
||||
|
||||
// Release the interface
|
||||
libusb_release_interface(dev->openDev, 0);
|
||||
|
||||
// Close the USB device
|
||||
libusb_close(dev->openDev);
|
||||
|
||||
// Free the device struct
|
||||
free(dev);
|
||||
}
|
||||
|
||||
sddc_range_t sddc_get_samplerate_range(sddc_dev_t* dev) {
|
||||
// All devices have the same samplerate range
|
||||
sddc_range_t range = { 8e6, 128e6, 0 };
|
||||
return range;
|
||||
}
|
||||
|
||||
int sddc_gpio_set(sddc_dev_t* dev, sddc_gpio_t gpios) {
|
||||
// Update the state
|
||||
dev->gpioState = gpios;
|
||||
|
||||
// Push to the device
|
||||
sddc_fx3_gpio(dev->openDev, gpios);
|
||||
}
|
||||
|
||||
int sddc_gpio_put(sddc_dev_t* dev, sddc_gpio_t gpios, bool value) {
|
||||
// Update the state of the given GPIOs only
|
||||
return sddc_gpio_set(dev, (dev->gpioState & (~gpios)) | (value ? gpios : 0));
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_samplerate(sddc_dev_t* dev, uint32_t samplerate) {
|
||||
// Update the state
|
||||
dev->samplerate = samplerate;
|
||||
|
||||
// If running, send the new sampling rate to the device
|
||||
if (dev->running) {
|
||||
int err = sddc_adc_set_samplerate(dev->openDev, samplerate);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_dithering(sddc_dev_t* dev, bool enabled) {
|
||||
// Update the GPIOs according to the desired state
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_DITHER, enabled);
|
||||
return (err < LIBUSB_SUCCESS) ? SDDC_ERROR_USB_ERROR : SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_randomizer(sddc_dev_t* dev, bool enabled) {
|
||||
// Update the GPIOs according to the desired state
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_RANDOM, enabled);
|
||||
return (err < LIBUSB_SUCCESS) ? SDDC_ERROR_USB_ERROR : SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_set_tuner_frequency(sddc_dev_t* dev, uint64_t frequency) {
|
||||
// Update the state
|
||||
dev->tunerFreq = frequency;
|
||||
|
||||
// If running, send the new frequency to the device
|
||||
if (dev->running) {
|
||||
int err = sddc_tuner_tune(dev->openDev, frequency);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
}
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_start(sddc_dev_t* dev) {
|
||||
// De-assert the shutdown pin
|
||||
int err = sddc_gpio_put(dev, SDDC_GPIO_SHUTDOWN, false);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Start the tuner (TODO: Check if in VHF mode)
|
||||
|
||||
// Start the ADC
|
||||
err = sddc_adc_set_samplerate(dev->openDev, dev->samplerate);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Start the FX3
|
||||
err = sddc_fx3_start(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Update the state
|
||||
dev->running = true;
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_stop(sddc_dev_t* dev) {
|
||||
// Stop the FX3
|
||||
int err = sddc_fx3_stop(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Stop the tuner
|
||||
err = sddc_tuner_stop(dev->openDev);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Stop the ADC
|
||||
err = sddc_adc_set_samplerate(dev->openDev, 0);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Set the GPIOs for standby mode
|
||||
err = sddc_gpio_put(dev, SDDC_GPIO_SHUTDOWN, true);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
|
||||
// Update the state
|
||||
dev->running = false;
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
sddc_error_t sddc_rx(sddc_dev_t* dev, int16_t* samples, int count) {
|
||||
// Read samples from the device
|
||||
int bytesRead = 0;
|
||||
int err = libusb_bulk_transfer(dev->openDev, LIBUSB_ENDPOINT_IN | 1, samples, count * sizeof(int16_t), &bytesRead, SDDC_TIMEOUT_MS);
|
||||
if (err < LIBUSB_SUCCESS) { return SDDC_ERROR_USB_ERROR; }
|
||||
return SDDC_SUCCESS;
|
||||
}
|
92
source_modules/sddc_source/libsddc/src/usb_interface.c
Normal file
92
source_modules/sddc_source/libsddc/src/usb_interface.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include "usb_interface.h"
|
||||
#include "fx3_boot.h"
|
||||
#include <stdio.h>
|
||||
|
||||
sddc_error_t sddc_init_device(libusb_device* dev, const char* firmware) {
|
||||
// Open the device
|
||||
libusb_device_handle* openDev;
|
||||
int err = libusb_open(dev, &openDev);
|
||||
if (err != LIBUSB_SUCCESS) {
|
||||
printf("Failed to open device: %d\n", err);
|
||||
return SDDC_ERROR_USB_ERROR;
|
||||
}
|
||||
|
||||
// Attempt to upload the firmware
|
||||
err = sddc_fx3_boot_upload_firmware(openDev, firmware);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to upload firmware to uninitialized device\n");
|
||||
return SDDC_ERROR_FIRMWARE_UPLOAD_FAILED;
|
||||
}
|
||||
|
||||
// Close the device
|
||||
libusb_close(openDev);
|
||||
|
||||
// Return successfully
|
||||
return SDDC_SUCCESS;
|
||||
}
|
||||
|
||||
int sddc_fx3_start(libusb_device_handle* dev) {
|
||||
// Send the start command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_START, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_stop(libusb_device_handle* dev) {
|
||||
// Send the stop command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_STOP, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_get_info(libusb_device_handle* dev, sddc_hwinfo_t* info, char enableDebug) {
|
||||
// Fetch the info data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_GET_INFO, enableDebug, 0, info, sizeof(sddc_hwinfo_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_gpio(libusb_device_handle* dev, sddc_gpio_t gpio) {
|
||||
// Send the GPIO state
|
||||
uint32_t dword = gpio;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_GPIO, 0, 0, &dword, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len) {
|
||||
// Send the I2C data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_I2C_W, addr, reg, data, len, SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_i2c_read(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len) {
|
||||
// Fetch the I2C data
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_I2C_R, addr, reg, data, len, SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_reset(libusb_device_handle* dev) {
|
||||
// Send the reset command
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_RESET, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_fx3_set_param(libusb_device_handle* dev, sddc_param_t param, uint16_t value) {
|
||||
// Send the parameter
|
||||
uint32_t dummy;
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_FX3_SET_PARAM, value, param, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_adc_set_samplerate(libusb_device_handle* dev, uint32_t samplerate) {
|
||||
// Send the samplerate
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_ADC_SET_RATE, 0, 0, &samplerate, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_start(libusb_device_handle* dev, uint32_t refFreq) {
|
||||
// Send the reset command
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_START, 0, 0, &refFreq, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_tune(libusb_device_handle* dev, uint64_t frequency) {
|
||||
// Send the reset command
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_TUNE, 0, 0, &frequency, sizeof(uint64_t), SDDC_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
int sddc_tuner_stop(libusb_device_handle* dev) {
|
||||
// Send the reset command
|
||||
uint32_t dummy; // Because the shitty firmware absolute wants data to stop the tuner, this is dumb...
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, SDDC_CMD_TUNER_STOP, 0, 0, &dummy, sizeof(uint32_t), SDDC_TIMEOUT_MS);
|
||||
}
|
168
source_modules/sddc_source/libsddc/src/usb_interface.h
Normal file
168
source_modules/sddc_source/libsddc/src/usb_interface.h
Normal file
@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
#include <sddc.h>
|
||||
#include <stdint.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#define SDDC_UNINIT_VID 0x04B4
|
||||
#define SDDC_UNINIT_PID 0x00F3
|
||||
#define SDDC_VID 0x04B4
|
||||
#define SDDC_PID 0x00F1
|
||||
|
||||
#define SDDC_INIT_SEARCH_DELAY_MS 1000
|
||||
#define SDDC_TIMEOUT_MS 1000
|
||||
|
||||
enum sddc_command {
|
||||
SDDC_CMD_FX3_START = 0xAA,
|
||||
SDDC_CMD_FX3_STOP = 0xAB,
|
||||
SDDC_CMD_FX3_GET_INFO = 0xAC,
|
||||
SDDC_CMD_FX3_GPIO = 0xAD,
|
||||
SDDC_CMD_FX3_I2C_W = 0xAE,
|
||||
SDDC_CMD_FX3_I2C_R = 0xAF,
|
||||
SDDC_CMD_FX3_RESET = 0xB1,
|
||||
SDDC_CMD_FX3_SET_PARAM = 0xB6,
|
||||
SDDC_CMD_ADC_SET_RATE = 0xB2,
|
||||
SDDC_CMD_TUNER_START = 0xB4,
|
||||
SDDC_CMD_TUNER_TUNE = 0xB5,
|
||||
SDDC_CMD_TUNER_STOP = 0xB8,
|
||||
SDDC_CMD_READ_DEBUG = 0xBA
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct sddc_hwinfo {
|
||||
uint8_t model;
|
||||
uint8_t firmwareConfigH;
|
||||
uint8_t firmwareConfigL;
|
||||
uint8_t vendorRequestCount;
|
||||
};
|
||||
typedef struct sddc_hwinfo sddc_hwinfo_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
enum sddc_gpio {
|
||||
SDDC_GPIO_NONE = 0,
|
||||
SDDC_GPIO_ATT_LE = (1 << 0),
|
||||
SDDC_GPIO_ATT_CLK = (1 << 1),
|
||||
SDDC_GPIO_ATT_DATA = (1 << 2),
|
||||
SDDC_GPIO_SEL0 = (1 << 3),
|
||||
SDDC_GPIO_SEL1 = (1 << 4),
|
||||
SDDC_GPIO_SHUTDOWN = (1 << 5),
|
||||
SDDC_GPIO_DITHER = (1 << 6),
|
||||
SDDC_GPIO_RANDOM = (1 << 7),
|
||||
SDDC_GPIO_BIAST_HF = (1 << 8),
|
||||
SDDC_GPIO_BIAST_VHF = (1 << 9),
|
||||
SDDC_GPIO_LED_YELLOW = (1 << 10),
|
||||
SDDC_GPIO_LED_RED = (1 << 11),
|
||||
SDDC_GPIO_LED_BLUE = (1 << 12),
|
||||
SDDC_GPIO_ATT_SEL0 = (1 << 13),
|
||||
SDDC_GPIO_ATT_SEL1 = (1 << 14),
|
||||
SDDC_GPIO_VHF_EN = (1 << 15),
|
||||
SDDC_GPIO_PGA_EN = (1 << 16),
|
||||
SDDC_GPIO_ALL = ((1 << 17)-1)
|
||||
};
|
||||
typedef enum sddc_gpio sddc_gpio_t;
|
||||
|
||||
enum sddc_param {
|
||||
SDDC_PARAM_R82XX_ATT = 1,
|
||||
SDDC_PARAM_R83XX_VGA = 2,
|
||||
SDDC_PARAM_R83XX_SIDEBAND = 3,
|
||||
SDDC_PARAM_R83XX_HARMONIC = 4,
|
||||
SDDC_PARAM_DAT31_ATT = 10,
|
||||
SDDC_PARAM_AD8340_VGA = 11,
|
||||
SDDC_PARAM_PRESELECTOR = 12,
|
||||
SDDC_PARAM_VHF_ATT = 13
|
||||
};
|
||||
typedef enum sddc_param sddc_param_t;
|
||||
|
||||
/**
|
||||
* Initialize a device with a given firmware.
|
||||
* @param dev SDDC USB device entry to initialize.
|
||||
* @param firmware Path to the firmware image.
|
||||
*/
|
||||
sddc_error_t sddc_init_device(libusb_device* dev, const char* firmware);
|
||||
|
||||
/**
|
||||
* Start the FX3 streaming.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_start(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Stop the FX3 streaming.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_stop(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Get the hardware info of a device.
|
||||
* @param dev SDDC USB device.
|
||||
* @param info Hardware info struct to write the return info into.
|
||||
* @param enableDebug 1 to enable hardware debug mode, 0 otherwise.
|
||||
*/
|
||||
int sddc_fx3_get_info(libusb_device_handle* dev, sddc_hwinfo_t* info, char enableDebug);
|
||||
|
||||
/**
|
||||
* Set the state of the GPIO pins.
|
||||
* @param dev SDDC USB device.
|
||||
* @param gpio State of the GPIO pins.
|
||||
*/
|
||||
int sddc_fx3_gpio(libusb_device_handle* dev, sddc_gpio_t gpio);
|
||||
|
||||
/**
|
||||
* Write data to the I2C port.
|
||||
* @param dev SDDC USB device.
|
||||
* @param addr Address of the target I2C device.
|
||||
* @param reg Register to write data to.
|
||||
* @param data Data buffer to write.
|
||||
* @param len Number of bytes to write.
|
||||
*/
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Read data from the I2C port.
|
||||
* @param dev SDDC USB device.
|
||||
* @param addr Address of the target I2C device.
|
||||
* @param reg Register to read data from.
|
||||
* @param data Data buffer to read data into.
|
||||
* @param len Number of bytes to read.
|
||||
*/
|
||||
int sddc_fx3_i2c_write(libusb_device_handle* dev, uint8_t addr, uint16_t reg, const uint8_t* data, uint16_t len);
|
||||
|
||||
/**
|
||||
* Reset the FX3 into bootloader mode.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_fx3_reset(libusb_device_handle* dev);
|
||||
|
||||
/**
|
||||
* Set a device parameter.
|
||||
* @param dev SDDC USB device.
|
||||
* @param arg Parameter to set.
|
||||
* @param value Value to set the parameter to.
|
||||
*/
|
||||
int sddc_fx3_set_param(libusb_device_handle* dev, sddc_param_t param, uint16_t value);
|
||||
|
||||
/**
|
||||
* Set the ADC sampling rate.
|
||||
* @param dev SDDC USB device.
|
||||
* @param samplerate Sampling rate. 0 to stop the ADC.
|
||||
*/
|
||||
int sddc_adc_set_samplerate(libusb_device_handle* dev, uint32_t samplerate);
|
||||
|
||||
/**
|
||||
* Start the tuner.
|
||||
* @param dev SDDC USB device.
|
||||
* @param frequency Initial LO frequency.
|
||||
*/
|
||||
int sddc_tuner_start(libusb_device_handle* dev, uint32_t refFreq);
|
||||
|
||||
/**
|
||||
* Set the tuner's LO frequency.
|
||||
* @param dev SDDC USB device.
|
||||
* @param frequency New LO frequency.
|
||||
*/
|
||||
int sddc_tuner_tune(libusb_device_handle* dev, uint64_t frequency);
|
||||
|
||||
/**
|
||||
* Stop the tuner.
|
||||
* @param dev SDDC USB device.
|
||||
*/
|
||||
int sddc_tuner_stop(libusb_device_handle* dev);
|
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sddc_info)
|
||||
|
||||
# Get source files
|
||||
file(GLOB_RECURSE SRC "src/*.cpp")
|
||||
|
||||
# Create executable
|
||||
add_executable(${PROJECT_NAME} ${SRC})
|
||||
|
||||
# Link to librfnm
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE sddc)
|
||||
|
||||
# Create install directive
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <sddc.h>
|
||||
|
||||
int main() {
|
||||
// Set firmware image path for debugging
|
||||
sddc_set_firmware_path("C:/Users/ryzerth/Downloads/SDDC_FX3 (1).img");
|
||||
|
||||
// List available devices
|
||||
sddc_devinfo_t* devList;
|
||||
int count = sddc_get_device_list(&devList);
|
||||
if (count < 0) {
|
||||
fprintf(stderr, "Failed to list devices: %d\n", count);
|
||||
return -1;
|
||||
}
|
||||
else if (!count) {
|
||||
printf("No device found.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Show the devices in the list
|
||||
for (int i = 0; i < count; i++) {
|
||||
printf("Serial: %s\n", devList[i].serial);
|
||||
printf("Hardware: %s\n", sddc_model_to_string(devList[i].model));
|
||||
printf("Firmware: v%d.%d\n", devList[i].firmwareMajor, devList[i].firmwareMinor);
|
||||
|
||||
// Print separator if needed
|
||||
if (i != count-1) {
|
||||
printf("\n================================================\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Free the device list and exit
|
||||
sddc_free_device_list(devList);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sddc_rx)
|
||||
|
||||
# Get source files
|
||||
file(GLOB_RECURSE SRC "src/*.cpp")
|
||||
|
||||
# Create executable
|
||||
add_executable(${PROJECT_NAME} ${SRC})
|
||||
|
||||
# Link to librfnm
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE sddc)
|
||||
|
||||
# Create install directive
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
@ -0,0 +1,38 @@
|
||||
#include <stdio.h>
|
||||
#include <sddc.h>
|
||||
|
||||
int main() {
|
||||
// Set firmware image path for debugging
|
||||
sddc_set_firmware_path("C:/Users/ryzerth/Downloads/SDDC_FX3 (1).img");
|
||||
|
||||
// Open the device
|
||||
sddc_dev_t* dev;
|
||||
sddc_error_t err = sddc_open("0009072C00C40C32", &dev);
|
||||
if (err != SDDC_SUCCESS) {
|
||||
printf("Failed to open device: %s (%d)\n", sddc_error_to_string(err), err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Configure the device
|
||||
sddc_set_samplerate(dev, 8e6);
|
||||
|
||||
// Start the device
|
||||
sddc_start(dev);
|
||||
|
||||
// Continuous read samples
|
||||
const int bufSize = 1e6;
|
||||
int16_t* buffer = new int16_t[bufSize];
|
||||
while (true) {
|
||||
// Read
|
||||
sddc_error_t err = sddc_rx(dev, buffer, bufSize);
|
||||
printf("Samples received: %d\n", err);
|
||||
}
|
||||
|
||||
// Stop the device
|
||||
sddc_stop(dev);
|
||||
|
||||
// Close the device
|
||||
sddc_close(dev);
|
||||
|
||||
return 0;
|
||||
}
|
512
source_modules/sddc_source/src/main.cpp
Normal file
512
source_modules/sddc_source/src/main.cpp
Normal file
@ -0,0 +1,512 @@
|
||||
#include <imgui.h>
|
||||
#include <module.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/smgui.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <core.h>
|
||||
#include <utils/optionlist.h>
|
||||
#include <atomic>
|
||||
#include <sddc.h>
|
||||
|
||||
SDRPP_MOD_INFO{
|
||||
/* Name: */ "sddc_source",
|
||||
/* Description: */ "SDDC Source Module",
|
||||
/* Author: */ "Ryzerth",
|
||||
/* Version: */ 0, 2, 0,
|
||||
/* Max instances */ -1
|
||||
};
|
||||
|
||||
ConfigManager config;
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
|
||||
|
||||
class SDDCSourceModule : public ModuleManager::Instance {
|
||||
public:
|
||||
SDDCSourceModule(std::string name) {
|
||||
this->name = name;
|
||||
|
||||
// Set firmware image path for debugging
|
||||
sddc_set_firmware_path("C:/Users/ryzerth/Downloads/SDDC_FX3 (1).img");
|
||||
|
||||
sampleRate = 128e6;
|
||||
|
||||
// Initialize the DDC
|
||||
ddc.init(&ddcIn, 50e6, 50e6, 50e6, 0.0);
|
||||
|
||||
handler.ctx = this;
|
||||
handler.selectHandler = menuSelected;
|
||||
handler.deselectHandler = menuDeselected;
|
||||
handler.menuHandler = menuHandler;
|
||||
handler.startHandler = start;
|
||||
handler.stopHandler = stop;
|
||||
handler.tuneHandler = tune;
|
||||
handler.stream = &ddc.out;
|
||||
|
||||
// Refresh devices
|
||||
refresh();
|
||||
|
||||
// Select device from config
|
||||
config.acquire();
|
||||
std::string devSerial = config.conf["device"];
|
||||
config.release();
|
||||
select(devSerial);
|
||||
|
||||
sigpath::sourceManager.registerSource("SDDC", &handler);
|
||||
}
|
||||
|
||||
~SDDCSourceModule() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void postInit() {}
|
||||
|
||||
void enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
bool isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
enum Port {
|
||||
PORT_RF,
|
||||
PORT_HF1,
|
||||
PORT_HF2
|
||||
};
|
||||
|
||||
private:
|
||||
std::string getBandwdithScaled(double bw) {
|
||||
char buf[1024];
|
||||
if (bw >= 1000000.0) {
|
||||
sprintf(buf, "%.1lfMHz", bw / 1000000.0);
|
||||
}
|
||||
else if (bw >= 1000.0) {
|
||||
sprintf(buf, "%.1lfKHz", bw / 1000.0);
|
||||
}
|
||||
else {
|
||||
sprintf(buf, "%.1lfHz", bw);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
devices.clear();
|
||||
|
||||
// // Get device list
|
||||
// sddc_devinfo_t* devList;
|
||||
// int count = sddc_get_device_list(&devList);
|
||||
// if (count < 0) {
|
||||
// flog::error("Failed to list SDDC devices: {}", count);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Add every device found
|
||||
// for (int i = 0; i < count; i++) {
|
||||
// // Create device name
|
||||
// std::string name = sddc_model_to_string(devList[i].model);
|
||||
// name += '[';
|
||||
// name += devList[i].serial;
|
||||
// name += ']';
|
||||
|
||||
// // Add an entry to the device list
|
||||
// devices.define(devList[i].serial, name, devList[i].serial);
|
||||
// }
|
||||
|
||||
devices.define("0009072C00C40C32", "TESTING", "0009072C00C40C32");
|
||||
|
||||
// // Free the device list
|
||||
// sddc_free_device_list(devList);
|
||||
}
|
||||
|
||||
void select(const std::string& serial) {
|
||||
// If there are no devices, give up
|
||||
if (devices.empty()) {
|
||||
selectedSerial.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the serial was not found, select the first available serial
|
||||
if (!devices.keyExists(serial)) {
|
||||
select(devices.key(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the ID in the list
|
||||
int id = devices.keyId(serial);
|
||||
|
||||
// Open the device
|
||||
sddc_dev_t* dev;
|
||||
int err = sddc_open(serial.c_str(), &dev);
|
||||
if (err) {
|
||||
flog::error("Failed to open device: {}", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate samplerate list
|
||||
samplerates.clear();
|
||||
samplerates.define(4e6, "4 MHz", 4e6);
|
||||
samplerates.define(8e6, "8 MHz", 8e6);
|
||||
samplerates.define(16e6, "16 MHz", 16e6);
|
||||
samplerates.define(32e6, "32 MHz", 32e6);
|
||||
samplerates.define(64e6, "64 MHz", 64e6);
|
||||
|
||||
// // Define the ports
|
||||
// ports.clear();
|
||||
// ports.define("hf", "HF", PORT_RF);
|
||||
// ports.define("vhf", "VHF", PORT_HF1);
|
||||
|
||||
// Close the device
|
||||
sddc_close(dev);
|
||||
|
||||
// Save serial number
|
||||
selectedSerial = serial;
|
||||
devId = id;
|
||||
|
||||
// Load default options
|
||||
sampleRate = 64e6;
|
||||
srId = samplerates.valueId(sampleRate);
|
||||
// port = PORT_RF;
|
||||
// portId = ports.valueId(port);
|
||||
// lnaGain = 0;
|
||||
// vgaGain = 0;
|
||||
|
||||
// Load config
|
||||
config.acquire();
|
||||
if (config.conf["devices"][selectedSerial].contains("samplerate")) {
|
||||
int desiredSr = config.conf["devices"][selectedSerial]["samplerate"];
|
||||
if (samplerates.keyExists(desiredSr)) {
|
||||
srId = samplerates.keyId(desiredSr);
|
||||
sampleRate = samplerates[srId];
|
||||
}
|
||||
}
|
||||
// if (config.conf["devices"][selectedSerial].contains("port")) {
|
||||
// std::string desiredPort = config.conf["devices"][selectedSerial]["port"];
|
||||
// if (ports.keyExists(desiredPort)) {
|
||||
// portId = ports.keyId(desiredPort);
|
||||
// port = ports[portId];
|
||||
// }
|
||||
// }
|
||||
// if (config.conf["devices"][selectedSerial].contains("lnaGain")) {
|
||||
// lnaGain = std::clamp<int>(config.conf["devices"][selectedSerial]["lnaGain"], FOBOS_LNA_GAIN_MIN, FOBOS_LNA_GAIN_MAX);
|
||||
// }
|
||||
// if (config.conf["devices"][selectedSerial].contains("vgaGain")) {
|
||||
// vgaGain = std::clamp<int>(config.conf["devices"][selectedSerial]["vgaGain"], FOBOS_VGA_GAIN_MIN, FOBOS_VGA_GAIN_MAX);
|
||||
// }
|
||||
config.release();
|
||||
|
||||
// Update the samplerate
|
||||
core::setInputSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
static void menuSelected(void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
flog::info("SDDCSourceModule '{0}': Menu Select!", _this->name);
|
||||
}
|
||||
|
||||
static void menuDeselected(void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
flog::info("SDDCSourceModule '{0}': Menu Deselect!", _this->name);
|
||||
}
|
||||
|
||||
static void start(void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
if (_this->running) { return; }
|
||||
|
||||
// Open the device
|
||||
sddc_error_t err = sddc_open(_this->selectedSerial.c_str(), &_this->openDev);
|
||||
if (err) {
|
||||
flog::error("Failed to open device: {}", (int)err);
|
||||
return;
|
||||
}
|
||||
|
||||
// // Get the selected port
|
||||
// _this->port = _this->ports[_this->portId];
|
||||
|
||||
// Configure the device
|
||||
sddc_set_samplerate(_this->openDev, _this->sampleRate * 2);
|
||||
|
||||
// // Configure the DDC
|
||||
// if (_this->port == PORT_RF && _this->sampleRate >= 50e6) {
|
||||
// // Set the frequency
|
||||
// fobos_rx_set_frequency(_this->openDev, _this->freq, &actualFreq);
|
||||
// }
|
||||
// else if (_this->port == PORT_RF) {
|
||||
// // Set the frequency
|
||||
// fobos_rx_set_frequency(_this->openDev, _this->freq, &actualFreq);
|
||||
|
||||
// // Configure and start the DDC for decimation only
|
||||
// _this->ddc.setInSamplerate(actualSr);
|
||||
// _this->ddc.setOutSamplerate(_this->sampleRate, _this->sampleRate);
|
||||
// _this->ddc.setOffset(0.0);
|
||||
// _this->ddc.start();
|
||||
// }
|
||||
// else {
|
||||
// Configure and start the DDC
|
||||
_this->ddc.setInSamplerate(_this->sampleRate * 2);
|
||||
_this->ddc.setOutSamplerate(_this->sampleRate, _this->sampleRate);
|
||||
_this->ddc.setOffset(_this->freq);
|
||||
_this->ddc.start();
|
||||
// }
|
||||
|
||||
// Compute buffer size (Lower than usual, but it's a workaround for their API having broken streaming)
|
||||
_this->bufferSize = _this->sampleRate / 100.0;
|
||||
|
||||
// Start streaming
|
||||
err = sddc_start(_this->openDev);
|
||||
if (err) {
|
||||
flog::error("Failed to start stream: {}", (int)err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start worker
|
||||
_this->run = true;
|
||||
_this->workerThread = std::thread(&SDDCSourceModule::worker, _this);
|
||||
|
||||
_this->running = true;
|
||||
flog::info("SDDCSourceModule '{0}': Start!", _this->name);
|
||||
}
|
||||
|
||||
static void stop(void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
if (!_this->running) { return; }
|
||||
_this->running = false;
|
||||
|
||||
// Stop worker
|
||||
_this->run = false;
|
||||
if (_this->port == PORT_RF && _this->sampleRate >= 50e6) {
|
||||
_this->ddc.out.stopWriter();
|
||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
||||
_this->ddc.out.clearWriteStop();
|
||||
}
|
||||
else {
|
||||
_this->ddcIn.stopWriter();
|
||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
||||
_this->ddcIn.clearWriteStop();
|
||||
}
|
||||
|
||||
// Stop streaming
|
||||
sddc_stop(_this->openDev);
|
||||
|
||||
// Stop the DDC
|
||||
_this->ddc.stop();
|
||||
|
||||
// Close the device
|
||||
sddc_close(_this->openDev);
|
||||
|
||||
flog::info("SDDCSourceModule '{0}': Stop!", _this->name);
|
||||
}
|
||||
|
||||
static void tune(double freq, void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
if (_this->running) {
|
||||
// if (_this->port == PORT_RF) {
|
||||
// double actual; // Dummy, don't care
|
||||
// //fobos_rx_set_frequency(_this->openDev, freq, &actual);
|
||||
// }
|
||||
// else {
|
||||
_this->ddc.setOffset(freq);
|
||||
// }
|
||||
}
|
||||
_this->freq = freq;
|
||||
flog::info("SDDCSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||
}
|
||||
|
||||
static void menuHandler(void* ctx) {
|
||||
SDDCSourceModule* _this = (SDDCSourceModule*)ctx;
|
||||
|
||||
if (_this->running) { SmGui::BeginDisabled(); }
|
||||
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Combo(CONCAT("##_sddc_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||
_this->select(_this->devices.key(_this->devId));
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
config.acquire();
|
||||
config.conf["device"] = _this->selectedSerial;
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
if (SmGui::Combo(CONCAT("##_sddc_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
||||
_this->sampleRate = _this->samplerates.value(_this->srId);
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
if (!_this->selectedSerial.empty()) {
|
||||
config.acquire();
|
||||
config.conf["devices"][_this->selectedSerial]["samplerate"] = _this->samplerates.key(_this->srId);
|
||||
config.release(true);
|
||||
}
|
||||
}
|
||||
|
||||
SmGui::SameLine();
|
||||
SmGui::FillWidth();
|
||||
SmGui::ForceSync();
|
||||
if (SmGui::Button(CONCAT("Refresh##_sddc_refr_", _this->name))) {
|
||||
_this->refresh();
|
||||
_this->select(_this->selectedSerial);
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
}
|
||||
|
||||
// SmGui::LeftLabel("Antenna Port");
|
||||
// SmGui::FillWidth();
|
||||
// if (SmGui::Combo(CONCAT("##_sddc_port_", _this->name), &_this->portId, _this->ports.txt)) {
|
||||
// if (!_this->selectedSerial.empty()) {
|
||||
// config.acquire();
|
||||
// config.conf["devices"][_this->selectedSerial]["port"] = _this->ports.key(_this->portId);
|
||||
// config.release(true);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (_this->running) { SmGui::EndDisabled(); }
|
||||
|
||||
// if (_this->port == PORT_RF) {
|
||||
// SmGui::LeftLabel("LNA Gain");
|
||||
// SmGui::FillWidth();
|
||||
// if (SmGui::SliderInt(CONCAT("##_sddc_lna_gain_", _this->name), &_this->lnaGain, FOBOS_LNA_GAIN_MIN, FOBOS_LNA_GAIN_MAX)) {
|
||||
// if (_this->running) {
|
||||
// fobos_rx_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||
// }
|
||||
// if (!_this->selectedSerial.empty()) {
|
||||
// config.acquire();
|
||||
// config.conf["devices"][_this->selectedSerial]["lnaGain"] = _this->lnaGain;
|
||||
// config.release(true);
|
||||
// }
|
||||
// }
|
||||
|
||||
// SmGui::LeftLabel("VGA Gain");
|
||||
// SmGui::FillWidth();
|
||||
// if (SmGui::SliderInt(CONCAT("##_sddc_vga_gain_", _this->name), &_this->vgaGain, FOBOS_VGA_GAIN_MIN, FOBOS_VGA_GAIN_MAX)) {
|
||||
// if (_this->running) {
|
||||
// fobos_rx_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||
// }
|
||||
// if (!_this->selectedSerial.empty()) {
|
||||
// config.acquire();
|
||||
// config.conf["devices"][_this->selectedSerial]["vgaGain"] = _this->vgaGain;
|
||||
// config.release(true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void worker() {
|
||||
// // Select different processing depending on the mode
|
||||
// if (port == PORT_RF && sampleRate >= 50e6) {
|
||||
// while (run) {
|
||||
// // Read samples
|
||||
// unsigned int sampCount = 0;
|
||||
// int err = fobos_rx_read_sync(openDev, (float*)ddc.out.writeBuf, &sampCount);
|
||||
// if (err) { break; }
|
||||
|
||||
// // Send out samples to the core
|
||||
// if (!ddc.out.swap(sampCount)) { break; }
|
||||
// }
|
||||
// }
|
||||
// else if (port == PORT_RF) {
|
||||
// while (run) {
|
||||
// // Read samples
|
||||
// unsigned int sampCount = 0;
|
||||
// int err = fobos_rx_read_sync(openDev, (float*)ddcIn.writeBuf, &sampCount);
|
||||
// if (err) { break; }
|
||||
|
||||
// // Send samples to the DDC
|
||||
// if (!ddcIn.swap(sampCount)) { break; }
|
||||
// }
|
||||
// }
|
||||
// else if (port == PORT_HF1) {
|
||||
// while (run) {
|
||||
// // Read samples
|
||||
// unsigned int sampCount = 0;
|
||||
// int err = fobos_rx_read_sync(openDev, (float*)ddcIn.writeBuf, &sampCount);
|
||||
// if (err) { break; }
|
||||
|
||||
// // Null out the HF2 samples
|
||||
// for (int i = 0; i < sampCount; i++) {
|
||||
// ddcIn.writeBuf[i].im = 0.0f;
|
||||
// }
|
||||
|
||||
// // Send samples to the DDC
|
||||
// if (!ddcIn.swap(sampCount)) { break; }
|
||||
// }
|
||||
// }
|
||||
// else if (port == PORT_HF2) {
|
||||
// Allocate the sample buffer
|
||||
int16_t* buffer = dsp::buffer::alloc<int16_t>(bufferSize);
|
||||
float* fbuffer = dsp::buffer::alloc<float>(bufferSize);
|
||||
float* nullBuffer = dsp::buffer::alloc<float>(bufferSize);
|
||||
|
||||
// Clear the null buffer
|
||||
dsp::buffer::clear(nullBuffer, bufferSize);
|
||||
|
||||
while (run) {
|
||||
// Read samples
|
||||
int err = sddc_rx(openDev, buffer, bufferSize);
|
||||
if (err) { break; }
|
||||
|
||||
// Convert the samples to float
|
||||
volk_16i_s32f_convert_32f(fbuffer, buffer, 32768.0f, bufferSize);
|
||||
|
||||
// Interleave into a complex value
|
||||
volk_32f_x2_interleave_32fc((lv_32fc_t*)ddcIn.writeBuf, fbuffer, nullBuffer, bufferSize);
|
||||
|
||||
// Send samples to the DDC
|
||||
if (!ddcIn.swap(bufferSize)) { break; }
|
||||
}
|
||||
|
||||
// Free the buffer
|
||||
dsp::buffer::free(buffer);
|
||||
// }
|
||||
}
|
||||
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
double sampleRate;
|
||||
SourceManager::SourceHandler handler;
|
||||
bool running = false;
|
||||
double freq;
|
||||
|
||||
OptionList<std::string, std::string> devices;
|
||||
OptionList<int, int> samplerates;
|
||||
OptionList<std::string, Port> ports;
|
||||
int devId = 0;
|
||||
int srId = 0;
|
||||
int portId = 0;
|
||||
Port port;
|
||||
int lnaGain = 0;
|
||||
int vgaGain = 0;
|
||||
std::string selectedSerial;
|
||||
|
||||
sddc_dev_t* openDev;
|
||||
|
||||
int bufferSize;
|
||||
std::thread workerThread;
|
||||
std::atomic<bool> run = false;
|
||||
|
||||
dsp::stream<dsp::complex_t> ddcIn;
|
||||
dsp::channel::RxVFO ddc;
|
||||
};
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
json def = json({});
|
||||
def["devices"] = json({});
|
||||
def["device"] = "";
|
||||
config.setPath(core::args["root"].s() + "/sddc_config.json");
|
||||
config.load(def);
|
||||
config.enableAutoSave();
|
||||
}
|
||||
|
||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||
return new SDDCSourceModule(name);
|
||||
}
|
||||
|
||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||
delete (SDDCSourceModule*)instance;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _END_() {
|
||||
config.disableAutoSave();
|
||||
config.save();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user