1 /*
2  * Copyright (C) 2022 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 #pragma once
18 
19 #include <hardware/sensors.h>
20 
21 #include <algorithm>
22 #include <deque>
23 
24 // A utility class that reads sensor samples from a direct channel buffer.
25 // Direct channel operates in a lockless manner and uses an atomic counter for
26 // synchronization. This class implements the counter based synchronization
27 // protocol and therefore guarantees data consistency. See
28 // https://developer.android.com/reference/android/hardware/SensorDirectChannel
29 // for more details on the atomic counter.
30 //
31 // Besides reading samples, the reader also supports keeping track of recently
32 // obtained samples.
33 //
34 // DirectChannelBufferReader is not thread safe. It's the caller's responsibility
35 // to serialize the calls, including the access to the returned sample
36 // container.
37 //
38 // Example usage:
39 //   DirectChannelBufferReader reader(buf, 100);
40 //
41 //   int num_samples = reader.Read();
42 //   const std::deque<sensors_event_t>& samples = reader.GetSampleContainer();
43 //   for (auto it = samples.end() - num_samples; it != samples.end(); it++) {
44 //     HandleNewSamples(*it);
45 //   }
46 //
47 //   int num_samples_skipped;
48 //   reader.Read(&num_samples_skipped);
49 //   if (num_samples_skipped > 0) {
50 //     ReportMissedSamples(num_samples_skipped);
51 //   }
52 //
53 //
54 // Another example:
55 //
56 //   DirectChannelBufferReader reader(buf, 100);
57 //
58 //   std::vector<sensors_event_t> Query(int start_time, int end_time) {
59 //     reader.Read();
60 //     std::vector<sensors_event_t> output;
61 //     for (auto& sample : reader_.GetSampleContainer()) {
62 //       if (sample.timestamp >= start_time && sample.timestamp < end_time) {
63 //         output.push_back(sample);
64 //       }
65 //     }
66 //     return output;
67 //   }
68 
69 class DirectChannelBufferReader {
70    public:
71     static constexpr int kErrorHeadOfBufferNotFound = -1;
72 
73     // Constructor
74     // direct_channel_buffer: Pointer to the shared buffer where sensor samples
75     //                        are written into.
76     // buffer_size_samples: The size of direct_channel_buffer in number of
77     //                      samples.
78     DirectChannelBufferReader(const sensors_event_t* direct_channel_buffer,
79                               int buffer_size_samples);
80 
~DirectChannelBufferReader()81     virtual ~DirectChannelBufferReader() {}
82 
83     // Attempts to read samples from the direct channel buffer. Returns
84     // the number of samples read, or kErrorHeadOfBufferNotFound if the reader
85     // can not find the write head e.g. due to corrupted data in the buffer.
86     // The function is non-blocking and returns 0 if new samples are not available.
87     // The caller should control its polling based on external factors like
88     // events in a different subsystem (e.g. camera frame ready)
89     // After the call completes, the caller can use GetSampleContainer() to
90     // access the samples. Sometimes it may be possible for one or more samples
91     // in the direct channel buffer to be overwritten by the writter before the
92     // reader has a chance to read it, e.g. when the reader does not keep up
93     // with the writer. The number of samples that were lost / skipped is
94     // written to <num_samples_skipped>, if the argument is not null.
95     int Read(int* num_samples_skipped = nullptr);
96 
97     // Returns the container that holds recent samples. New samples are appended
98     // to the end of the container when Read() is called. Samples from previous
99     // rounds of Read() are kept around in the container, except when the total
100     // samples exceeds <buffer_size_samples> - 1, in which case older samples
101     // would be truncated. The caller is free to remove samples from the
102     // container, e.g. after the samples are consumed.
103     //
104     // Calls to the returned container must be synchronized with calls to this
105     // instance of DirectChannelBufferReader.
GetSampleContainer()106     std::deque<sensors_event_t>& GetSampleContainer() { return buffer_; }
107 
108    protected:
109     // For test only.
110     virtual const sensors_event_t ReadOneSample(int index);
111 
112    private:
113     // Truncates the head of <buffer_> until its size <= buffer_size_samples - 1.
114     void TruncateBuffer();
115 
116     // Points to the direct channel buffer where the sensor writes samples into.
117     const volatile sensors_event_t* direct_channel_buffer_;
118 
119     // The number of samples that <direct_channel_buffer_> is able to hold.
120     const int buffer_size_samples_;
121 
122     // The atomic counter value of the last valid sample.
123     int64_t last_atomic_counter_ = 0;
124 
125     // The index into <direct_channel_buffer_> that should be read next time.
126     int index_ = 0;
127 
128     // The number of successive sensors_event_t reads with consecutive atomic
129     // counters values.
130     // E.g. 1           => streak_ = 1
131     //      5 6 7       => streak_ = 3
132     //      1 2 3 14    => streak_ = 1
133     //      1 2 3 14 15 => streak_ = 2
134     int streak_ = 0;
135 
136     // The buffer holding recent samples.
137     std::deque<sensors_event_t> buffer_;
138 };
139