/* * 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 #include #include #include #include #include #include #include #include "directchannel.h" #include "eventnums.h" #include "halIntf.h" #include "hubdefs.h" #include "ring.h" #include #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" #define MAX_ALTERNATES 2 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); void releaseWakeLockIfAppropriate(); //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 saveSensorSettings() const; void setRawScale(float scaleAccel, float scaleMag) { mScaleAccel = scaleAccel; mScaleMag = scaleMag; } void setLeftyMode(bool enable); 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 protectIfWakeEventLocked(int32_t sensor); ssize_t decrementIfWakeEventLocked(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(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 LeftyState { bool accel; // Process wrist-aware accel samples as lefty mode bool gyro; // Process wrist-aware gyro samples as lefty mode bool hub; // Sensor hub is currently operating in lefty mode }; struct Flush { int handle; uint8_t count; // Used to synchronize the transition in and out of // lefty mode between nanohub and the AP. bool internal; }; struct SensorState { uint64_t latency; uint64_t lastTimestamp; uint64_t desiredTSample; rate_q10_t rate; uint8_t sensorType; uint8_t primary; uint8_t alt[MAX_ALTERNATES]; 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; int32_t mWriteFailures; float mMagBias[3]; uint8_t mMagAccuracy; uint8_t mMagAccuracyRestore; float mGyroBias[3], mAccelBias[3], mAccelEnabledBias[3]; bool mAccelEnabledBiasStored; GyroOtcData mGyroOtcData; float mScaleAccel, mScaleMag; LeftyState mLefty; SensorState mSensorState[NUM_COMMS_SENSORS_PLUS_1]; std::list mFlushesPending[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; } ssize_t sendCmd(const void *buf, size_t count); void initConfigCmd(struct ConfigCmd *cmd, int handle); void queueFlushInternal(int handle, bool internal); void queueDataInternal(int handle, void *data, size_t length); void discardInotifyEvent(); void waitOnNanohubLock(); void initNanohubLock(); void restoreSensorState(); void sendCalibrationOffsets(); // Enable SCHED_FIFO priority for main thread void enableSchedFifoMode(); #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); bool isSampleIntervalSatisfied(int handle, uint64_t timestamp); void updateSampleRate(int handle, int reason); #ifdef DIRECT_REPORT_ENABLED int stopAllDirectReportOnChannel( int channel_handle, std::vector *unstoppedSensors); uint64_t rateLevelToDeviceSamplingPeriodNs(int handle, int rateLevel) const; inline static bool intervalLargeEnough(uint64_t actual, uint64_t desired) { return (actual + (actual >> 4)) >= desired; // >= 94.11% of desired } struct DirectChannelTimingInfo{ uint64_t lastTimestamp; int rateLevel; }; Mutex mDirectChannelLock; //sensor_handle=>(channel_handle => DirectChannelTimingInfo) std::unordered_map > mSensorToChannel; //channel_handle=>ptr of Channel obj std::unordered_map> mDirectChannel; int32_t mDirectChannelHandle; #endif DISALLOW_EVIL_CONSTRUCTORS(HubConnection); }; } // namespace android #endif // HUB_CONNECTION_H_