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