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
debounceTimerCallback(uint32_t timerId,void * cookie)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
hallIsr(struct ChainedIsr * localIsr)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
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)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
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)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
hallPower(bool on,void * cookie)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
hallFirmwareUpload(void * cookie)157 static bool hallFirmwareUpload(void *cookie)
158 {
159 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
160 }
161
hallSetRate(uint32_t rate,uint64_t latency,void * cookie)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
hallFlush(void * cookie)176 static bool hallFlush(void *cookie)
177 {
178 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL);
179 }
180
hallSendLastSample(void * cookie,uint32_t tid)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
handleEvent(uint32_t evtType,const void * evtData)203 static void handleEvent(uint32_t evtType, const void* evtData)
204 {
205 }
206
startTask(uint32_t taskId)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
endTask(void)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