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 50 static 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 64 static 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 83 static 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 104 static 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 113 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr) 114 { 115 extiUnchainIsr(HALL_IRQ, isr); 116 extiDisableIntGpio(pin); 117 return true; 118 } 119 120 static const uint32_t supportedRates[] = 121 { 122 SENSOR_RATE_ONCHANGE, 123 0 124 }; 125 126 static 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 136 static 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 157 static bool hallFirmwareUpload(void *cookie) 158 { 159 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0); 160 } 161 162 static 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 176 static bool hallFlush(void *cookie) 177 { 178 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL); 179 } 180 181 static 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 194 static const struct SensorOps mSensorOps = 195 { 196 .sensorPower = hallPower, 197 .sensorFirmwareUpload = hallFirmwareUpload, 198 .sensorSetRate = hallSetRate, 199 .sensorFlush = hallFlush, 200 .sensorSendOneDirectEvt = hallSendLastSample 201 }; 202 203 static void handleEvent(uint32_t evtType, const void* evtData) 204 { 205 } 206 207 static 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 218 static 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 227 INTERNAL_APP_INIT(APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 6), APP_VERSION, startTask, endTask, handleEvent); 228