You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
4.6KB

  1. // Copyright 2013 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. //
  25. // -----------------------------------------------------------------------------
  26. //
  27. // QPSK demodulator for firmware updater.
  28. #ifndef STM_AUDIO_BOOTLOADER_DEMODULATOR_H_
  29. #define STM_AUDIO_BOOTLOADER_DEMODULATOR_H_
  30. #include "stmlib/stmlib.h"
  31. #include "stmlib/utils/ring_buffer.h"
  32. namespace stm_audio_bootloader {
  33. enum DemodulatorState {
  34. DEMODULATOR_STATE_ESTIMATE_DC_COMPONENT,
  35. DEMODULATOR_STATE_ESTIMATE_POWER,
  36. DEMODULATOR_STATE_CARRIER_SYNC,
  37. DEMODULATOR_STATE_DECISION_SYNC,
  38. DEMODULATOR_STATE_OVERFLOW,
  39. DEMODULATOR_STATE_OK
  40. };
  41. const uint16_t kFilterSize = 7;
  42. const uint16_t kHistorySize = 256;
  43. // Works because kHistorySize is a power of 2!
  44. const uint16_t kHistoryMask = kHistorySize - 1;
  45. class Demodulator {
  46. public:
  47. Demodulator() { }
  48. ~Demodulator() { }
  49. void Init(
  50. uint32_t phase_increment,
  51. uint16_t cutoff_reciprocal,
  52. uint16_t symbol_duration);
  53. inline void PushSample(int16_t sample) {
  54. if (!samples_.writable()) {
  55. state_ = DEMODULATOR_STATE_OVERFLOW;
  56. }
  57. samples_.Overwrite(sample);
  58. }
  59. inline void SyncCarrier(bool discover) {
  60. skipped_samples_ = skipped_symbols_ = 0;
  61. samples_.Flush();
  62. symbols_.Flush();
  63. state_ = discover
  64. ? DEMODULATOR_STATE_ESTIMATE_DC_COMPONENT
  65. : DEMODULATOR_STATE_CARRIER_SYNC;
  66. phase_ = phase_error_ = 0;
  67. }
  68. inline void SyncDecision() {
  69. symbols_.Flush();
  70. state_ = DEMODULATOR_STATE_DECISION_SYNC;
  71. correlation_history_[0] = correlation_history_[1] = -1024;
  72. correlation_maximum_ = 0;
  73. skipped_symbols_ = 0;
  74. }
  75. inline size_t available() const {
  76. return symbols_.readable();
  77. }
  78. DemodulatorState state() const { return state_; }
  79. inline void ProcessAtLeast(size_t size) {
  80. if (samples_.readable() >= size) {
  81. while (samples_.readable()) {
  82. if (state_ == DEMODULATOR_STATE_ESTIMATE_DC_COMPONENT) {
  83. EstimateDcComponent();
  84. } else if (state_ == DEMODULATOR_STATE_ESTIMATE_POWER) {
  85. EstimatePower();
  86. } else {
  87. Demodulate();
  88. }
  89. }
  90. }
  91. }
  92. inline uint8_t NextSymbol() {
  93. return symbols_.ImmediateRead();
  94. }
  95. inline int32_t q() const { return q_history_[history_ptr_]; }
  96. inline int32_t i() const { return i_history_[history_ptr_]; }
  97. private:
  98. void Reset();
  99. void EstimateDcComponent();
  100. void EstimatePower();
  101. void Demodulate();
  102. int16_t DecideSymbol(bool adjust_timing);
  103. DemodulatorState state_;
  104. int32_t dc_offset_;
  105. uint32_t skipped_samples_;
  106. uint32_t power_;
  107. // Local oscillator.
  108. uint32_t phase_;
  109. uint32_t phase_increment_;
  110. int32_t phase_error_;
  111. // Demodulator filter.
  112. int32_t filter_coefficients_[kFilterSize];
  113. int32_t q_taps_[kFilterSize];
  114. int32_t i_taps_[kFilterSize];
  115. // History of demodulated signal for matched filter and decision.
  116. int16_t q_history_[kHistorySize];
  117. int16_t i_history_[kHistorySize];
  118. uint16_t history_ptr_;
  119. // Correlator between the demodulated signal and the synchronization
  120. // template.
  121. int32_t correlation_history_[2];
  122. int32_t correlation_maximum_;
  123. // Decision timing.
  124. uint16_t symbol_duration_;
  125. uint16_t decision_counter_;
  126. uint16_t skipped_symbols_;
  127. stmlib::RingBuffer<int16_t, 1024> samples_;
  128. stmlib::RingBuffer<uint8_t, 128> symbols_;
  129. DISALLOW_COPY_AND_ASSIGN(Demodulator);
  130. };
  131. } // namespace stm_audio_bootloader
  132. #endif // STM_AUDIO_BOOTLOADER_DEMODULATOR_H_