1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
18 #define ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
19 
20 #include <math.h>
21 #include <memory.h>
22 #include <stdlib.h>
23 #include "ManchesterEncoder.h"
24 
25 /**
26  * Encode bytes using Manchester Code.
27  * Round the edges using a half cosine to reduce ringing caused by a hard edge.
28  */
29 
30 class RoundedManchesterEncoder : public ManchesterEncoder {
31 public:
RoundedManchesterEncoder(int samplesPerPulse)32     RoundedManchesterEncoder(int samplesPerPulse)
33             : ManchesterEncoder(samplesPerPulse) {
34         int rampSize = samplesPerPulse / 4;
35         mZeroAfterZero = std::make_unique<float[]>(samplesPerPulse);
36         mZeroAfterOne = std::make_unique<float[]>(samplesPerPulse);
37 
38         int sampleIndex = 0;
39         for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
40             float phase = (rampIndex + 1) * M_PI / rampSize;
41             float sample = -cosf(phase);
42             mZeroAfterZero[sampleIndex] = sample;
43             mZeroAfterOne[sampleIndex] = 1.0f;
44             sampleIndex++;
45         }
46         for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
47             mZeroAfterZero[sampleIndex] = 1.0f;
48             mZeroAfterOne[sampleIndex] = 1.0f;
49             sampleIndex++;
50         }
51         for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
52             float phase = (rampIndex + 1) * M_PI / rampSize;
53             float sample = cosf(phase);
54             mZeroAfterZero[sampleIndex] = sample;
55             mZeroAfterOne[sampleIndex] = sample;
56             sampleIndex++;
57         }
58         for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) {
59             mZeroAfterZero[sampleIndex] = -1.0f;
60             mZeroAfterOne[sampleIndex] = -1.0f;
61             sampleIndex++;
62         }
63     }
64 
onNextBit(bool current)65     void onNextBit(bool current) override {
66         // Do we need to use the rounded edge?
67         mCurrentSamples = (current ^ mPreviousBit)
68                           ? mZeroAfterOne.get()
69                           : mZeroAfterZero.get();
70         mPreviousBit = current;
71     }
72 
nextFloat()73     float nextFloat() override {
74         advanceSample();
75         float output = mCurrentSamples[mCursor];
76         if (getCurrentBit()) output = -output;
77         return output;
78     }
79 
80 private:
81 
82     bool mPreviousBit = false;
83     float *mCurrentSamples = nullptr;
84     std::unique_ptr<float[]> mZeroAfterZero;
85     std::unique_ptr<float[]> mZeroAfterOne;
86 };
87 
88 #endif //ANALYZER_ROUNDED_MANCHESTER_ENCODER_H
89