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_ID APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 11) 36 #define APP_VERSION 2 37 38 #define HALL_REPORT_OPENED_VALUE 0 39 #define HALL_REPORT_CLOSED_VALUE 1 40 #define HALL_DEBOUNCE_TIMER_DELAY 25000000ULL // 25 milliseconds 41 42 #ifndef HALL_S_PIN 43 #error "HALL_S_PIN is not defined; please define in variant.h" 44 #endif 45 #ifndef HALL_S_IRQ 46 #error "HALL_S_IRQ is not defined; please define in variant.h" 47 #endif 48 #ifndef HALL_N_PIN 49 #error "HALL_N_PIN is not defined; please define in variant.h" 50 #endif 51 #ifndef HALL_N_IRQ 52 #error "HALL_N_IRQ is not defined; please define in variant.h" 53 #endif 54 55 #define MAKE_TYPE(sPin,nPin) (sPin ? HALL_REPORT_OPENED_VALUE : HALL_REPORT_CLOSED_VALUE) + \ 56 ((nPin ? HALL_REPORT_OPENED_VALUE : HALL_REPORT_CLOSED_VALUE) << 1) 57 58 static struct SensorTask 59 { 60 struct Gpio *sPin; 61 struct Gpio *nPin; 62 struct ChainedIsr sIsr; 63 struct ChainedIsr nIsr; 64 65 uint32_t id; 66 uint32_t sensorHandle; 67 uint32_t debounceTimerHandle; 68 69 int32_t prevReportedState; 70 71 bool on; 72 } mTask; 73 74 static void hallReportState(int32_t pinState) 75 { 76 union EmbeddedDataPoint sample; 77 if (pinState != mTask.prevReportedState) { 78 mTask.prevReportedState = pinState; 79 sample.idata = pinState; 80 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL); 81 } 82 } 83 84 static void debounceTimerCallback(uint32_t timerId, void *cookie) 85 { 86 int32_t prevPinState = (int32_t)cookie; 87 int32_t currPinState = MAKE_TYPE(gpioGet(mTask.sPin), gpioGet(mTask.nPin)); 88 89 if (mTask.on && (currPinState == prevPinState)) { 90 hallReportState(currPinState); 91 } 92 } 93 94 static void startDebounceTimer(struct SensorTask *data) 95 { 96 int32_t currPinState = MAKE_TYPE(gpioGet(data->sPin), gpioGet(data->nPin)); 97 if (data->debounceTimerHandle) 98 timTimerCancel(data->debounceTimerHandle); 99 100 data->debounceTimerHandle = timTimerSet(HALL_DEBOUNCE_TIMER_DELAY, 0, 50, debounceTimerCallback, (void*)currPinState, true /* oneShot */); 101 } 102 103 static bool hallSouthIsr(struct ChainedIsr *localIsr) 104 { 105 struct SensorTask *data = container_of(localIsr, struct SensorTask, sIsr); 106 if (data->on) 107 startDebounceTimer(data); 108 extiClearPendingGpio(data->sPin); 109 return true; 110 } 111 112 static bool hallNorthIsr(struct ChainedIsr *localIsr) 113 { 114 struct SensorTask *data = container_of(localIsr, struct SensorTask, nIsr); 115 if (data->on) 116 startDebounceTimer(data); 117 extiClearPendingGpio(data->nPin); 118 return true; 119 } 120 121 static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, IRQn_Type irqn) 122 { 123 gpioConfigInput(pin, GPIO_SPEED_LOW, GPIO_PULL_NONE); 124 syscfgSetExtiPort(pin); 125 extiEnableIntGpio(pin, EXTI_TRIGGER_BOTH); 126 extiChainIsr(irqn, isr); 127 return true; 128 } 129 130 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, IRQn_Type irqn) 131 { 132 extiUnchainIsr(irqn, isr); 133 extiDisableIntGpio(pin); 134 return true; 135 } 136 137 static const uint32_t supportedRates[] = 138 { 139 SENSOR_RATE_ONCHANGE, 140 0 141 }; 142 143 static const struct SensorInfo mSensorInfo = 144 { 145 .sensorName = "Hall", 146 .supportedRates = supportedRates, 147 .sensorType = SENS_TYPE_HALL, 148 .numAxis = NUM_AXIS_EMBEDDED, 149 .interrupt = NANOHUB_INT_WAKEUP, 150 .minSamples = 20 151 }; 152 153 static bool hallPower(bool on, void *cookie) 154 { 155 if (on) { 156 extiClearPendingGpio(mTask.sPin); 157 extiClearPendingGpio(mTask.nPin); 158 enableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ); 159 enableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ); 160 } else { 161 disableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ); 162 disableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ); 163 extiClearPendingGpio(mTask.sPin); 164 extiClearPendingGpio(mTask.nPin); 165 } 166 167 mTask.on = on; 168 mTask.prevReportedState = -1; 169 170 if (mTask.debounceTimerHandle) { 171 timTimerCancel(mTask.debounceTimerHandle); 172 mTask.debounceTimerHandle = 0; 173 } 174 175 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0); 176 } 177 178 static bool hallFirmwareUpload(void *cookie) 179 { 180 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0); 181 } 182 183 static bool hallSetRate(uint32_t rate, uint64_t latency, void *cookie) 184 { 185 // report initial state of hall interrupt pin 186 if (mTask.on) 187 hallReportState(MAKE_TYPE(gpioGet(mTask.sPin), gpioGet(mTask.nPin))); 188 189 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency); 190 } 191 192 static bool hallFlush(void *cookie) 193 { 194 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL); 195 } 196 197 static bool hallSendLastSample(void *cookie, uint32_t tid) 198 { 199 union EmbeddedDataPoint sample; 200 bool result = true; 201 202 if (mTask.prevReportedState != -1) { 203 sample.idata = mTask.prevReportedState; 204 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL, tid); 205 } 206 207 return result; 208 } 209 210 static const struct SensorOps mSensorOps = 211 { 212 .sensorPower = hallPower, 213 .sensorFirmwareUpload = hallFirmwareUpload, 214 .sensorSetRate = hallSetRate, 215 .sensorFlush = hallFlush, 216 .sensorSendOneDirectEvt = hallSendLastSample 217 }; 218 219 static void handleEvent(uint32_t evtType, const void* evtData) 220 { 221 } 222 223 static bool startTask(uint32_t taskId) 224 { 225 mTask.id = taskId; 226 mTask.sensorHandle = sensorRegister(&mSensorInfo, &mSensorOps, NULL, true); 227 mTask.prevReportedState = -1; 228 mTask.sPin = gpioRequest(HALL_S_PIN); 229 mTask.nPin = gpioRequest(HALL_N_PIN); 230 mTask.sIsr.func = hallSouthIsr; 231 mTask.nIsr.func = hallNorthIsr; 232 233 return true; 234 } 235 236 static void endTask(void) 237 { 238 disableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ); 239 disableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ); 240 extiUnchainIsr(HALL_S_IRQ, &mTask.sIsr); 241 extiUnchainIsr(HALL_N_IRQ, &mTask.nIsr); 242 extiClearPendingGpio(mTask.sPin); 243 extiClearPendingGpio(mTask.nPin); 244 gpioRelease(mTask.sPin); 245 gpioRelease(mTask.nPin); 246 sensorUnregister(mTask.sensorHandle); 247 memset(&mTask, 0, sizeof(struct SensorTask)); 248 } 249 250 INTERNAL_APP_INIT(APP_ID, APP_VERSION, startTask, endTask, handleEvent); 251