1/* 2 * Copyright (C) 2016 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#include <stdlib.h> 18#include <string.h> 19#include <float.h> 20 21#include <eventnums.h> 22#include <gpio.h> 23#include <heap.h> 24#include <hostIntf.h> 25#include <isr.h> 26#include <nanohubPacket.h> 27#include <sensors.h> 28#include <seos.h> 29#include <timer.h> 30#include <plat/gpio.h> 31#include <plat/exti.h> 32#include <plat/syscfg.h> 33#include <variant/variant.h> 34 35#define APP_VERSION 2 36 37#define HALL_REPORT_OPENED_VALUE 0 38#define HALL_REPORT_CLOSED_VALUE 1 39#define HALL_DEBOUNCE_TIMER_DELAY 25000000ULL // 25 milliseconds 40 41#ifndef HALL_PIN 42#error "HALL_PIN is not defined; please define in variant.h" 43#endif 44 45#ifndef HALL_IRQ 46#error "HALL_IRQ is not defined; please define in variant.h" 47#endif 48 49 50static struct SensorTask 51{ 52 struct Gpio *pin; 53 struct ChainedIsr isr; 54 55 uint32_t id; 56 uint32_t sensorHandle; 57 uint32_t debounceTimerHandle; 58 59 int32_t prevReportedValue; 60 61 bool on; 62} mTask; 63 64static void debounceTimerCallback(uint32_t timerId, void *cookie) 65{ 66 union EmbeddedDataPoint sample; 67 bool prevPinState = (bool)cookie; 68 bool pinState = gpioGet(mTask.pin); 69 70 if (mTask.on) { 71 if (pinState == prevPinState) { 72 sample.idata = pinState ? HALL_REPORT_OPENED_VALUE : 73 HALL_REPORT_CLOSED_VALUE; 74 75 if (sample.idata != mTask.prevReportedValue) { 76 mTask.prevReportedValue = sample.idata; 77 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL); 78 } 79 } 80 } 81} 82 83static bool hallIsr(struct ChainedIsr *localIsr) 84{ 85 struct SensorTask *data = container_of(localIsr, struct SensorTask, isr); 86 bool pinState = gpioGet(data->pin); 87 88 if (!extiIsPendingGpio(data->pin)) { 89 return false; 90 } 91 92 if (data->on) { 93 if (mTask.debounceTimerHandle) 94 timTimerCancel(mTask.debounceTimerHandle); 95 96 mTask.debounceTimerHandle = timTimerSet(HALL_DEBOUNCE_TIMER_DELAY, 0, 50, debounceTimerCallback, (void*)pinState, true /* oneShot */); 97 } 98 99 100 extiClearPendingGpio(data->pin); 101 return true; 102} 103 104static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr) 105{ 106 gpioConfigInput(pin, GPIO_SPEED_LOW, GPIO_PULL_NONE); 107 syscfgSetExtiPort(pin); 108 extiEnableIntGpio(pin, EXTI_TRIGGER_BOTH); 109 extiChainIsr(HALL_IRQ, isr); 110 return true; 111} 112 113static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr) 114{ 115 extiUnchainIsr(HALL_IRQ, isr); 116 extiDisableIntGpio(pin); 117 return true; 118} 119 120static const uint32_t supportedRates[] = 121{ 122 SENSOR_RATE_ONCHANGE, 123 0 124}; 125 126static const struct SensorInfo mSensorInfo = 127{ 128 .sensorName = "Hall", 129 .supportedRates = supportedRates, 130 .sensorType = SENS_TYPE_HALL, 131 .numAxis = NUM_AXIS_EMBEDDED, 132 .interrupt = NANOHUB_INT_WAKEUP, 133 .minSamples = 20 134}; 135 136static bool hallPower(bool on, void *cookie) 137{ 138 if (on) { 139 extiClearPendingGpio(mTask.pin); 140 enableInterrupt(mTask.pin, &mTask.isr); 141 } else { 142 disableInterrupt(mTask.pin, &mTask.isr); 143 extiClearPendingGpio(mTask.pin); 144 } 145 146 mTask.on = on; 147 mTask.prevReportedValue = -1; 148 149 if (mTask.debounceTimerHandle) { 150 timTimerCancel(mTask.debounceTimerHandle); 151 mTask.debounceTimerHandle = 0; 152 } 153 154 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0); 155} 156 157static bool hallFirmwareUpload(void *cookie) 158{ 159 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0); 160} 161 162static bool hallSetRate(uint32_t rate, uint64_t latency, void *cookie) 163{ 164 // report initial state of hall interrupt pin 165 if (mTask.on) { 166 union EmbeddedDataPoint sample; 167 bool pinState = gpioGet(mTask.pin); 168 sample.idata = pinState ? HALL_REPORT_OPENED_VALUE : 169 HALL_REPORT_CLOSED_VALUE; 170 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL); 171 } 172 173 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency); 174} 175 176static bool hallFlush(void *cookie) 177{ 178 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL); 179} 180 181static bool hallSendLastSample(void *cookie, uint32_t tid) 182{ 183 union EmbeddedDataPoint sample; 184 bool result = true; 185 186 if (mTask.prevReportedValue != -1) { 187 sample.idata = mTask.prevReportedValue; 188 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL, tid); 189 } 190 191 return result; 192} 193 194static const struct SensorOps mSensorOps = 195{ 196 .sensorPower = hallPower, 197 .sensorFirmwareUpload = hallFirmwareUpload, 198 .sensorSetRate = hallSetRate, 199 .sensorFlush = hallFlush, 200 .sensorSendOneDirectEvt = hallSendLastSample 201}; 202 203static void handleEvent(uint32_t evtType, const void* evtData) 204{ 205} 206 207static bool startTask(uint32_t taskId) 208{ 209 mTask.id = taskId; 210 mTask.sensorHandle = sensorRegister(&mSensorInfo, &mSensorOps, NULL, true); 211 mTask.prevReportedValue = -1; 212 mTask.pin = gpioRequest(HALL_PIN); 213 mTask.isr.func = hallIsr; 214 215 return true; 216} 217 218static void endTask(void) 219{ 220 disableInterrupt(mTask.pin, &mTask.isr); 221 extiUnchainIsr(HALL_IRQ, &mTask.isr); 222 extiClearPendingGpio(mTask.pin); 223 gpioRelease(mTask.pin); 224 sensorUnregister(mTask.sensorHandle); 225} 226 227INTERNAL_APP_INIT(APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 6), APP_VERSION, startTask, endTask, handleEvent); 228