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
hallReportState(int32_t pinState)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
debounceTimerCallback(uint32_t timerId,void * cookie)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
startDebounceTimer(struct SensorTask * data)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
hallSouthIsr(struct ChainedIsr * localIsr)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
hallNorthIsr(struct ChainedIsr * localIsr)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
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr,IRQn_Type irqn)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
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr,IRQn_Type irqn)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
hallPower(bool on,void * cookie)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
hallFirmwareUpload(void * cookie)178 static bool hallFirmwareUpload(void *cookie)
179 {
180 return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
181 }
182
hallSetRate(uint32_t rate,uint64_t latency,void * cookie)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
hallFlush(void * cookie)192 static bool hallFlush(void *cookie)
193 {
194 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL);
195 }
196
hallSendLastSample(void * cookie,uint32_t tid)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
handleEvent(uint32_t evtType,const void * evtData)219 static void handleEvent(uint32_t evtType, const void* evtData)
220 {
221 }
222
startTask(uint32_t taskId)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
endTask(void)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