| /* |
| * 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 <list> |
| |
| #include "directchannel.h" |
| #include "eventnums.h" |
| #include "halIntf.h" |
| #include "hubdefs.h" |
| #include "ring.h" |
| |
| #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" |
| |
| #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<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 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<struct Flush> 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<int32_t> *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<int32_t, |
| std::unordered_map<int32_t, DirectChannelTimingInfo> > 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_ |