SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
lorademod.cpp
Go to the documentation of this file.
1 // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
3 // written by Christian Daniel //
4 // (c) 2015 John Greb
5 // //
6 // This program is free software; you can redistribute it and/or modify //
7 // it under the terms of the GNU General Public License as published by //
8 // the Free Software Foundation as version 3 of the License, or //
9 // (at your option) any later version. //
10 // //
11 // This program is distributed in the hope that it will be useful, //
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
14 // GNU General Public License V3 for more details. //
15 // //
16 // You should have received a copy of the GNU General Public License //
17 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
19 
20 
21 #include <QTime>
22 #include <QDebug>
23 #include <stdio.h>
24 
25 #include "dsp/downchannelizer.h"
27 #include "dsp/dspcommands.h"
28 #include "device/deviceapi.h"
29 
30 #include "lorademod.h"
31 #include "lorabits.h"
32 
35 
36 const QString LoRaDemod::m_channelIdURI = "sdrangel.channel.lorademod";
37 const QString LoRaDemod::m_channelId = "LoRaDemod";
38 
40  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
41  m_deviceAPI(deviceAPI),
42  m_sampleSink(0),
43  m_settingsMutex(QMutex::Recursive)
44 {
45  setObjectName(m_channelId);
46 
48  m_sampleRate = 96000;
49  m_frequency = 0;
53 
54  m_chirp = 0;
55  m_angle = 0;
56  m_bin = 0;
57  m_result = 0;
58  m_count = 0;
59  m_header = 0;
60  m_time = 0;
61  m_tune = 0;
62 
65 
66  mov = new float[4*LORA_SFFT_LEN];
67  history = new short[1024];
68  finetune = new short[16];
69 
70  m_channelizer = new DownChannelizer(this);
74 }
75 
77 {
78  if (loraFilter)
79  delete loraFilter;
80  if (negaFilter)
81  delete negaFilter;
82  if (mov)
83  delete [] mov;
84  if (history)
85  delete [] history;
86  if (finetune)
87  delete [] finetune;
88 
91  delete m_threadedChannelizer;
92  delete m_channelizer;
93 }
94 
96 {
97  short bin, j, max;
98  char text[256];
99 
100  max = m_time / 4 - 3;
101 
102  if (max > 140)
103  {
104  max = 140; // about 2 symbols to each char
105  }
106 
107  for ( j=0; j < max; j++)
108  {
109  bin = (history[(j + 1) * 4] + m_tune ) & (LORA_SFFT_LEN - 1);
110  text[j] = toGray(bin >> 1);
111  }
112 
113  prng6(text, max);
114  // First block is always 8 symbols
115  interleave6(text, 6);
116  interleave6(&text[8], max);
117  hamming6(text, 6);
118  hamming6(&text[8], max);
119 
120  for ( j=0; j < max / 2; j++)
121  {
122  text[j] = (text[j * 2 + 1] << 4) | (0xf & text[j * 2 + 0]);
123 
124  if ((text[j] < 32 )||( text[j] > 126))
125  {
126  text[j] = 0x5f;
127  }
128  }
129 
130  text[3] = text[2];
131  text[2] = text[1];
132  text[1] = text[0];
133  text[j] = 0;
134 
135  printf("%s\n", &text[1]);
136 }
137 
138 short LoRaDemod::synch(short bin)
139 {
140  short i, j;
141 
142  if (bin < 0)
143  {
144  if (m_time > 70)
145  {
146  dumpRaw();
147  }
148 
149  m_time = 0;
150  return -1;
151  }
152 
153  history[m_time] = bin;
154 
155  if (m_time > 12)
156  {
157  if (bin == history[m_time - 6])
158  {
159  if (bin == history[m_time - 12])
160  {
161  m_tune = LORA_SFFT_LEN - bin;
162  j = 0;
163 
164  for (i=0; i<12; i++)
165  {
166  j += finetune[15 & (m_time - i)];
167  }
168 
169  if (j < 0)
170  {
171  m_tune += 1;
172  }
173 
174  m_tune &= (LORA_SFFT_LEN - 1);
175  m_time = 0;
176  return -1;
177  }
178  }
179  }
180 
181  m_time++;
182  m_time &= 1023;
183 
184  if (m_time & 3)
185  {
186  return -1;
187  }
188 
189  return (bin + m_tune) & (LORA_SFFT_LEN - 1);
190 }
191 
193 {
194  int p, q;
195  short i, result, negresult, movpoint;
196  float peak, negpeak, tfloat;
197  float mag[LORA_SFFT_LEN];
198  float rev[LORA_SFFT_LEN];
199 
200  loraFilter->run(c * a);
201  negaFilter->run(c * conj(a));
202 
203  // process spectrum twice in FFTLEN
204  if (++m_count & ((1 << DATA_BITS) - 1))
205  {
206  return m_result;
207  }
208 
209  movpoint = 3 & (m_count >> DATA_BITS);
210 
211  loraFilter->fetch(mag);
212  negaFilter->fetch(rev);
213  peak = negpeak = 0.0f;
214  result = negresult = 0;
215 
216  for (i = 0; i < LORA_SFFT_LEN; i++)
217  {
218  if (rev[i] > negpeak)
219  {
220  negpeak = rev[i];
221  negresult = i;
222  }
223 
224  tfloat = mov[i] + mov[LORA_SFFT_LEN + i] +mov[2 * LORA_SFFT_LEN + i]
225  + mov[3 * LORA_SFFT_LEN + i] + mag[i];
226 
227  if (tfloat > peak)
228  {
229  peak = tfloat;
230  result = i;
231  }
232 
233  mov[movpoint * LORA_SFFT_LEN + i] = mag[i];
234  }
235 
236  p = (result - 1 + LORA_SFFT_LEN) & (LORA_SFFT_LEN -1);
237  q = (result + 1) & (LORA_SFFT_LEN -1);
238  finetune[15 & m_time] = (mag[p] > mag[q]) ? -1 : 1;
239 
240  if (peak < negpeak * LORA_SQUELCH)
241  {
242  result = -1;
243  }
244 
245  result = synch(result);
246 
247  if (result >= 0)
248  {
249  m_result = result;
250  }
251 
252  return m_result;
253 }
254 
255 void LoRaDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool pO)
256 {
257  (void) pO;
258  int newangle;
259  Complex ci;
260 
261  m_sampleBuffer.clear();
262 
263  m_settingsMutex.lock();
264 
265  for(SampleVector::const_iterator it = begin; it < end; ++it)
266  {
267  Complex c(it->real() / SDR_RX_SCALEF, it->imag() / SDR_RX_SCALEF);
268  c *= m_nco.nextIQ();
269 
271  {
272  m_chirp = (m_chirp + 1) & (SPREADFACTOR - 1);
273  m_angle = (m_angle + m_chirp) & (SPREADFACTOR - 1);
275  newangle = detect(ci, cangle);
276 
277  m_bin = (m_bin + newangle) & (LORA_SFFT_LEN - 1);
279  m_sampleBuffer.push_back(Sample(nangle.real() * 100, nangle.imag() * 100));
281  }
282  }
283 
284  if(m_sampleSink != 0)
285  {
286  m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
287  }
288 
289  m_settingsMutex.unlock();
290 }
291 
293 {
294 }
295 
297 {
298 }
299 
301 {
302  qDebug() << "LoRaDemod::handleMessage";
303 
305  {
307 
308  m_settingsMutex.lock();
309 
310  m_sampleRate = notif.getSampleRate();
314 
315  m_settingsMutex.unlock();
316 
317  qDebug() << "LoRaDemod::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
318  << " frequencyOffset: " << notif.getFrequencyOffset();
319 
320  return true;
321  }
322  else if (MsgConfigureChannelizer::match(cmd))
323  {
325 
327  cfg.getSampleRate(),
328  cfg.getCenterFrequency());
329 
330  qDebug() << "LoRaDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
331  << " centerFrequency: " << cfg.getCenterFrequency();
332 
333  return true;
334  }
335  else if (MsgConfigureLoRaDemod::match(cmd))
336  {
338 
339  m_settingsMutex.lock();
340 
341  LoRaDemodSettings settings = cfg.getSettings();
342 
345 
346  m_settingsMutex.unlock();
347 
348  m_settings = settings;
349  qDebug() << "LoRaDemod::handleMessage: MsgConfigureLoRaDemod: m_Bandwidth: " << m_Bandwidth;
350 
351  return true;
352  }
353  else if (DSPSignalNotification::match(cmd))
354  {
355  return true;
356  }
357  else
358  {
359  if(m_sampleSink != 0)
360  {
361  return m_sampleSink->handleMessage(cmd);
362  }
363  else
364  {
365  return false;
366  }
367  }
368 }
369 
370 QByteArray LoRaDemod::serialize() const
371 {
372  return m_settings.serialize();
373 }
374 
375 bool LoRaDemod::deserialize(const QByteArray& data)
376 {
377  if (m_settings.deserialize(data))
378  {
381  return true;
382  }
383  else
384  {
388  return false;
389  }
390 }
391 
short * finetune
Definition: lorademod.h:152
int detect(Complex sample, Complex angle)
Definition: lorademod.cpp:192
short toGray(short bin)
Definition: lorabits.h:36
Complex nextIQ()
Return next complex sample.
Definition: nco.cpp:61
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
Fixed< IntType, IntBits > cos(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2271
sfft * negaFilter
Definition: lorademod.h:149
NCO m_nco
Definition: lorademod.h:154
int m_angle
Definition: lorademod.h:140
void removeChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:163
void addChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:156
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
float * mov
Definition: lorademod.h:150
virtual bool deserialize(const QByteArray &data)
Definition: lorademod.cpp:375
int m_bin
Definition: lorademod.h:141
virtual ~LoRaDemod()
Definition: lorademod.cpp:76
void prng6(char *inout, int size)
Definition: lorabits.h:63
Real m_sampleDistanceRemain
Definition: lorademod.h:156
#define LORA_SQUELCH
Definition: lorademod.h:38
Definition: fftfilt.h:96
int m_result
Definition: lorademod.h:142
DownChannelizer * m_channelizer
Definition: lorademod.h:133
static const int bandwidths[]
sfft * loraFilter
Definition: lorademod.h:148
#define M_PI
Definition: rdsdemod.cpp:27
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
bool deserialize(const QByteArray &data)
static MsgConfigureLoRaDemod * create(const LoRaDemodSettings &settings, bool force)
Definition: lorademod.h:53
#define SDR_RX_SCALEF
Definition: dsptypes.h:33
void fetch(float *result)
Definition: fftfilt.cpp:451
virtual void stop()
Definition: lorademod.cpp:296
static const QString m_channelId
Definition: lorademod.h:120
BasebandSampleSink * m_sampleSink
Definition: lorademod.h:158
int m_chirp
Definition: lorademod.h:139
virtual bool handleMessage(const Message &cmd)=0
Processing of a message. Returns true if message has actually been processed.
void run(const cmplx &input)
Definition: fftfilt.cpp:437
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
#define SPREADFACTOR
Definition: lorademod.h:36
Interpolator m_interpolator
Definition: lorademod.h:155
Fixed< IntType, IntBits > sin(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2265
QMutex m_settingsMutex
Definition: lorademod.h:160
int32_t i
Definition: decimators.h:244
int m_frequency
Definition: lorademod.h:138
short m_tune
Definition: lorademod.h:146
static bool match(const Message *message)
Definition: message.cpp:45
void setFreq(Real freq, Real sampleRate)
Definition: nco.cpp:49
int m_sampleRate
Definition: lorademod.h:137
void removeChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Remove a channel sink (Rx)
Definition: deviceapi.cpp:127
LoRaDemod(DeviceAPI *deviceAPI)
Definition: lorademod.cpp:39
ThreadedBasebandSampleSink * m_threadedChannelizer
Definition: lorademod.h:132
DeviceAPI * m_deviceAPI
Definition: lorademod.h:131
void interleave6(char *inout, int size)
Definition: lorabits.h:14
virtual void start()
Definition: lorademod.cpp:292
#define DATA_BITS
Definition: lorademod.h:34
void addChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Add a channel sink (Rx)
Definition: deviceapi.cpp:118
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: lorademod.cpp:300
int m_time
Definition: lorademod.h:145
LoRaDemodSettings m_settings
Definition: lorademod.h:134
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool pO)
Definition: lorademod.cpp:255
static const QString m_channelIdURI
Definition: lorademod.h:119
const LoRaDemodSettings & getSettings() const
Definition: lorademod.h:50
QByteArray serialize() const
int m_count
Definition: lorademod.h:143
Real m_Bandwidth
Definition: lorademod.h:136
int m_header
Definition: lorademod.h:144
#define LORA_SFFT_LEN
Definition: lorademod.h:37
short synch(short bin)
Definition: lorademod.cpp:138
virtual QByteArray serialize() const
Definition: lorademod.cpp:370
std::complex< Real > Complex
Definition: dsptypes.h:43
short * history
Definition: lorademod.h:151
SampleVector m_sampleBuffer
Definition: lorademod.h:159
float Real
Definition: dsptypes.h:42
void dumpRaw(void)
Definition: lorademod.cpp:95
T max(const T &x, const T &y)
Definition: framework.h:446
void hamming6(char *inout, int size)
Definition: lorabits.h:42