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