1 /*
2  * Copyright (C) 2019 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 #define ATRACE_TAG (ATRACE_TAG_VIBRATOR | ATRACE_TAG_HAL)
18 #define LOG_TAG "android.hardware.vibrator@1.3-service.coral"
19 
20 #include "Hardware.h"
21 
22 #include <log/log.h>
23 #include <utils/Trace.h>
24 
25 #include <iostream>
26 
27 namespace android {
28 namespace hardware {
29 namespace vibrator {
30 namespace V1_3 {
31 namespace implementation {
32 
33 template <typename T>
fileFromEnv(const char * env,T * outStream,std::string * outName=nullptr)34 static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
35     auto file = std::getenv(env);
36     auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
37 
38     if (file == nullptr) {
39         ALOGE("Failed get env %s", env);
40         return;
41     }
42 
43     if (outName != nullptr) {
44         *outName = std::string(file);
45     }
46 
47     // Force 'in' mode to prevent file creation
48     outStream->open(file, mode | std::ios_base::in);
49     if (!*outStream) {
50         ALOGE("Failed to open %s:%s (%d): %s", env, file, errno, strerror(errno));
51     }
52 }
53 
pathsFromEnv(const char * env)54 static auto pathsFromEnv(const char *env) {
55     std::map<std::string, std::ifstream> ret;
56     auto value = std::getenv(env);
57 
58     if (value == nullptr) {
59         return ret;
60     }
61 
62     std::istringstream paths{value};
63     std::string path;
64 
65     while (paths >> path) {
66         ret[path].open(path);
67     }
68 
69     return ret;
70 }
71 
trim(const std::string & str,const std::string & whitespace=" \\t")72 static std::string trim(const std::string &str, const std::string &whitespace = " \t") {
73     const auto str_begin = str.find_first_not_of(whitespace);
74     if (str_begin == std::string::npos) {
75         return "";
76     }
77 
78     const auto str_end = str.find_last_not_of(whitespace);
79     const auto str_range = str_end - str_begin + 1;
80 
81     return str.substr(str_begin, str_range);
82 }
83 
84 template <typename T>
unpack(std::istream & stream,T * value)85 static Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
86     for (auto &entry : *value) {
87         stream >> entry;
88     }
89 }
90 
91 template <typename T>
unpack(std::istream & stream,T * value)92 static Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
93     stream >> *value;
94 }
95 
96 #define RECORD(args...) record(__FUNCTION__, ##args)
97 
HwApi()98 HwApi::HwApi() {
99     // ostreams below are required
100     fileFromEnv("F0_FILEPATH", &mF0, &mNames[&mF0]);
101     fileFromEnv("REDC_FILEPATH", &mRedc, &mNames[&mRedc]);
102     fileFromEnv("Q_FILEPATH", &mQ, &mNames[&mQ]);
103     fileFromEnv("ACTIVATE_PATH", &mActivate, &mNames[&mActivate]);
104     fileFromEnv("DURATION_PATH", &mDuration, &mNames[&mDuration]);
105     fileFromEnv("STATE_PATH", &mState, &mNames[&mState]);
106     fileFromEnv("EFFECT_DURATION_PATH", &mEffectDuration, &mNames[&mEffectDuration]);
107     fileFromEnv("EFFECT_INDEX_PATH", &mEffectIndex, &mNames[&mEffectIndex]);
108     fileFromEnv("EFFECT_QUEUE_PATH", &mEffectQueue, &mNames[&mEffectQueue]);
109     fileFromEnv("EFFECT_SCALE_PATH", &mEffectScale, &mNames[&mEffectScale]);
110     fileFromEnv("GLOBAL_SCALE_PATH", &mGlobalScale, &mNames[&mGlobalScale]);
111     fileFromEnv("ASP_ENABLE_PATH", &mAspEnable, &mNames[&mAspEnable]);
112     fileFromEnv("GPIO_FALL_INDEX", &mGpioFallIndex, &mNames[&mGpioFallIndex]);
113     fileFromEnv("GPIO_FALL_SCALE", &mGpioFallScale, &mNames[&mGpioFallScale]);
114     fileFromEnv("GPIO_RISE_INDEX", &mGpioRiseIndex, &mNames[&mGpioRiseIndex]);
115     fileFromEnv("GPIO_RISE_SCALE", &mGpioRiseScale, &mNames[&mGpioRiseScale]);
116 }
117 
118 template <typename T>
has(T & stream)119 bool HwApi::has(T &stream) {
120     return !!stream;
121 }
122 
123 template <typename T, typename U>
get(T * value,U & stream)124 bool HwApi::get(T *value, U &stream) {
125     ATRACE_NAME("HwApi::get");
126     bool ret;
127     stream.seekg(0);
128     stream >> *value;
129     if (!(ret = !!stream)) {
130         ALOGE("Failed to read %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
131     }
132     stream.clear();
133     RECORD(*value, &stream);
134     return ret;
135 }
136 
137 template <typename T, typename U>
set(const T & value,U & stream)138 bool HwApi::set(const T &value, U &stream) {
139     ATRACE_NAME("HwApi::set");
140     bool ret;
141     stream << value << std::endl;
142     if (!(ret = !!stream)) {
143         ALOGE("Failed to write %s (%d): %s", mNames[&stream].c_str(), errno, strerror(errno));
144         stream.clear();
145     }
146     RECORD(value, &stream);
147     return ret;
148 }
149 
150 template <typename T>
record(const char * func,const T & value,void * stream)151 void HwApi::record(const char *func, const T &value, void *stream) {
152     mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
153     mRecords.erase(mRecords.begin());
154 }
155 
debug(int fd)156 void HwApi::debug(int fd) {
157     dprintf(fd, "Kernel:\n");
158 
159     for (auto &entry : pathsFromEnv("HWAPI_DEBUG_PATHS")) {
160         auto &path = entry.first;
161         auto &stream = entry.second;
162         std::string line;
163 
164         dprintf(fd, "  %s:\n", path.c_str());
165         while (std::getline(stream, line)) {
166             dprintf(fd, "    %s\n", line.c_str());
167         }
168     }
169 
170     dprintf(fd, "  Records:\n");
171     for (auto &r : mRecords) {
172         if (r == nullptr) {
173             continue;
174         }
175         dprintf(fd, "    %s\n", r->toString(mNames).c_str());
176     }
177 }
178 
179 template <typename T>
toString(const NamesMap & names)180 std::string HwApi::Record<T>::toString(const NamesMap &names) {
181     std::stringstream ret;
182 
183     ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
184 
185     return ret.str();
186 }
187 
HwCal()188 HwCal::HwCal() {
189     std::ifstream calfile;
190 
191     fileFromEnv("CALIBRATION_FILEPATH", &calfile);
192 
193     for (std::string line; std::getline(calfile, line);) {
194         if (line.empty() || line[0] == '#') {
195             continue;
196         }
197         std::istringstream is_line(line);
198         std::string key, value;
199         if (std::getline(is_line, key, ':') && std::getline(is_line, value)) {
200             mCalData[trim(key)] = trim(value);
201         }
202     }
203 }
204 
205 template <typename T>
get(const char * key,T * value)206 bool HwCal::get(const char *key, T *value) {
207     ATRACE_NAME("HwCal::get");
208     auto it = mCalData.find(key);
209     if (it == mCalData.end()) {
210         ALOGE("Missing %s config!", key);
211         return false;
212     }
213     std::stringstream stream{it->second};
214     unpack(stream, value);
215     if (!stream || !stream.eof()) {
216         ALOGE("Invalid %s config!", key);
217         return false;
218     }
219     return true;
220 }
221 
debug(int fd)222 void HwCal::debug(int fd) {
223     std::ifstream stream;
224     std::string path;
225     std::string line;
226 
227     dprintf(fd, "Persist:\n");
228 
229     fileFromEnv("CALIBRATION_FILEPATH", &stream, &path);
230 
231     dprintf(fd, "  %s:\n", path.c_str());
232     while (std::getline(stream, line)) {
233         dprintf(fd, "    %s\n", line.c_str());
234     }
235 }
236 
237 }  // namespace implementation
238 }  // namespace V1_3
239 }  // namespace vibrator
240 }  // namespace hardware
241 }  // namespace android
242