/*
* 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_