/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef HUB_CONNECTION_H_ #define HUB_CONNECTION_H_ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h> #include <utils/Errors.h> #include <utils/Mutex.h> #include <utils/Thread.h> #include "activityeventhandler.h" #include "directchannel.h" #include "eventnums.h" #include "halIntf.h" #include "hubdefs.h" #include "ring.h" #ifdef USE_SENSORSERVICE_TO_GET_FIFO #include <thread> #endif #include <unordered_map> #define WAKELOCK_NAME "sensorHal" #define ACCEL_BIAS_TAG "accel" #define ACCEL_SW_BIAS_TAG "accel_sw" #define GYRO_BIAS_TAG "gyro" #define GYRO_OTC_DATA_TAG "gyro_otc" #define GYRO_SW_BIAS_TAG "gyro_sw" #define MAG_BIAS_TAG "mag" namespace android { struct HubConnection : public Thread { static HubConnection *getInstance(); status_t initCheck() const; enum ProximitySensorType { PROXIMITY_UNKNOWN, PROXIMITY_ROHM, PROXIMITY_AMS, }; // Blocks until it can return a status status_t getAliveCheck(); virtual bool threadLoop(); void queueActivate(int handle, bool enable); void queueSetDelay(int handle, nsecs_t delayNs); void queueBatch(int handle, nsecs_t sampling_period_ns, nsecs_t max_report_latency_ns); void queueFlush(int handle); void queueData(int handle, void *data, size_t length); void setOperationParameter(const additional_info_event_t &info); bool isWakeEvent(int32_t sensor); void releaseWakeLockIfAppropriate(); ssize_t getWakeEventCount(); ssize_t decrementWakeEventCount(); //TODO: factor out event ring buffer functionality into a separate class ssize_t read(sensors_event_t *ev, size_t size); ssize_t write(const sensors_event_t *ev, size_t n); void setActivityCallback(ActivityEventHandler *eventHandler); void saveSensorSettings() const; void setRawScale(float scaleAccel, float scaleMag) { mScaleAccel = scaleAccel; mScaleMag = scaleMag; } protected: HubConnection(); virtual ~HubConnection(); virtual void onFirstRef(); private: typedef uint32_t rate_q10_t; // q10 means lower 10 bits are for fractions bool mWakelockHeld; int32_t mWakeEventCount; void protectIfWakeEvent(int32_t sensor); static inline uint64_t period_ns_to_frequency_q10(nsecs_t period_ns) { return 1024000000000ULL / period_ns; } static inline nsecs_t frequency_q10_to_period_ns(uint64_t frequency_q10) { if (frequency_q10) return 1024000000000LL / frequency_q10; else return (nsecs_t)0; } static inline uint64_t frequency_to_frequency_q10(float frequency) { return period_ns_to_frequency_q10(static_cast<nsecs_t>(1e9f/frequency)); } enum { CONFIG_CMD_DISABLE = 0, CONFIG_CMD_ENABLE = 1, CONFIG_CMD_FLUSH = 2, CONFIG_CMD_CFG_DATA = 3, CONFIG_CMD_CALIBRATE = 4, }; struct ConfigCmd { uint32_t evtType; uint64_t latency; rate_q10_t rate; uint8_t sensorType; uint8_t cmd; uint16_t flags; uint8_t data[]; } __attribute__((packed)); struct MsgCmd { uint32_t evtType; struct HostHubRawPacket msg; } __attribute__((packed)); struct SensorState { uint64_t latency; rate_q10_t rate; uint8_t sensorType; uint8_t alt; uint8_t flushCnt; bool enable; }; struct FirstSample { uint8_t numSamples; uint8_t numFlushes; uint8_t highAccuracy : 1; uint8_t biasPresent : 1; uint8_t biasSample : 6; uint8_t pad; }; struct RawThreeAxisSample { uint32_t deltaTime; int16_t ix, iy, iz; } __attribute__((packed)); struct ThreeAxisSample { uint32_t deltaTime; float x, y, z; } __attribute__((packed)); struct OneAxisSample { uint32_t deltaTime; union { float fdata; uint32_t idata; }; } __attribute__((packed)); // The following structure should match struct HostIntfDataBuffer found in // firmware/inc/hostIntf.h struct nAxisEvent { uint32_t evtType; union { struct { uint64_t referenceTime; union { struct FirstSample firstSample; struct OneAxisSample oneSamples[]; struct RawThreeAxisSample rawThreeSamples[]; struct ThreeAxisSample threeSamples[]; }; }; uint8_t buffer[]; }; } __attribute__((packed)); static Mutex sInstanceLock; static HubConnection *sInstance; // This lock is used for synchronization between the write thread (from // sensorservice) and the read thread polling from the nanohub driver. Mutex mLock; RingBuffer mRing; ActivityEventHandler *mActivityEventHandler; float mMagBias[3]; uint8_t mMagAccuracy; uint8_t mMagAccuracyRestore; float mGyroBias[3], mAccelBias[3]; GyroOtcData mGyroOtcData; float mScaleAccel, mScaleMag; SensorState mSensorState[NUM_COMMS_SENSORS_PLUS_1]; uint64_t mStepCounterOffset; uint64_t mLastStepCount; int mFd; int mInotifyPollIndex; struct pollfd mPollFds[4]; int mNumPollFds; sensors_event_t *initEv(sensors_event_t *ev, uint64_t timestamp, uint32_t type, uint32_t sensor); uint8_t magAccuracyUpdate(sensors_vec_t *sv); void processSample(uint64_t timestamp, uint32_t type, uint32_t sensor, struct OneAxisSample *sample, bool highAccuracy); void processSample(uint64_t timestamp, uint32_t type, uint32_t sensor, struct RawThreeAxisSample *sample, bool highAccuracy); void processSample(uint64_t timestamp, uint32_t type, uint32_t sensor, struct ThreeAxisSample *sample, bool highAccuracy); void postOsLog(uint8_t *buf, ssize_t len); void processAppData(uint8_t *buf, ssize_t len); ssize_t processBuf(uint8_t *buf, size_t len); inline bool isValidHandle(int handle) { return handle >= 0 && handle < NUM_COMMS_SENSORS_PLUS_1 && mSensorState[handle].sensorType; } void initConfigCmd(struct ConfigCmd *cmd, int handle); void queueDataInternal(int handle, void *data, size_t length); void discardInotifyEvent(); void waitOnNanohubLock(); void initNanohubLock(); void restoreSensorState(); void sendCalibrationOffsets(); #ifdef USE_SENSORSERVICE_TO_GET_FIFO // Enable SCHED_FIFO priority for main thread std::thread mEnableSchedFifoThread; #endif static void enableSchedFifoMode(sp<HubConnection> hub); #ifdef LID_STATE_REPORTING_ENABLED int mUinputFd; status_t initializeUinputNode(); void sendFolioEvent(int32_t data); #endif // LID_STATE_REPORTING_ENABLED #ifdef USB_MAG_BIAS_REPORTING_ENABLED int mMagBiasPollIndex; float mUsbMagBias; void queueUsbMagBias(); #endif // USB_MAG_BIAS_REPORTING_ENABLED #ifdef DOUBLE_TOUCH_ENABLED int mDoubleTouchPollIndex; #endif // DOUBLE_TOUCH_ENABLED // Direct report functions public: int addDirectChannel(const struct sensors_direct_mem_t *mem); int removeDirectChannel(int channel_handle); int configDirectReport(int sensor_handle, int channel_handle, int rate_level); bool isDirectReportSupported() const; private: void sendDirectReportEvent(const sensors_event_t *nev, size_t n); void mergeDirectReportRequest(struct ConfigCmd *cmd, int handle); #ifdef DIRECT_REPORT_ENABLED int stopAllDirectReportOnChannel( int channel_handle, std::vector<int32_t> *unstoppedSensors); Mutex mDirectChannelLock; //sensor_handle=>(channel_handle, rate_level) std::unordered_map<int32_t, std::unordered_map<int32_t, int32_t> > mSensorToChannel; //channel_handle=>ptr of Channel obj std::unordered_map<int32_t, std::unique_ptr<DirectChannelBase>> mDirectChannel; int32_t mDirectChannelHandle; #endif DISALLOW_EVIL_CONSTRUCTORS(HubConnection); }; } // namespace android #endif // HUB_CONNECTION_H_