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