+/*
+* Copyright (c) 2018 Samsung Electronics Co., Ltd.
+*
+* Licensed under the Flora License, Version 1.1 (the License);
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://floralicense.org/license/
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an AS IS BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <peripheral_io.h>
+#include <time.h>
+#include "log.h"
+
+
+#define GPIO_PIN 26
+#define MIN_LAP_TIME 5
+
+typedef struct _lap_counter_s {
+ peripheral_gpio_h gpio;
+ struct timespec last_timestamp;
+ uint32_t gpio_initial_value;
+ uint32_t gpio_prev_value;
+} lap_counter_s;
+
+static lap_counter_s s_info = { 0, };
+
+#define CHECK_GPIO_ERROR(pin, ret) \
+ if (ret != PERIPHERAL_ERROR_NONE) { \
+ peripheral_gpio_close(pin); \
+ _E("GPIO ERROR: %s, %s[%d]", get_error_message(ret), __FILE__, __LINE__); \
+ return; \
+ }
+
+void _print_time(const char *title, struct timespec *ts)
+{
+ char buf[PATH_MAX];
+ struct tm *_tm = localtime(&(ts->tv_sec));
+ strftime(&buf[0], PATH_MAX, "%H:%M:%S", _tm);
+
+ snprintf(&buf[strlen(buf)], PATH_MAX, ".%03ld", ts->tv_nsec / (long)1e6);
+
+ _D ("%s %s", title, buf);
+}
+
+static struct timespec _calculate_lap_time(struct timespec *prev, struct timespec *now)
+{
+ struct timespec lap;
+
+ lap.tv_sec = now->tv_sec - prev->tv_sec;
+ lap.tv_nsec = now->tv_nsec - prev->tv_nsec;
+
+
+ _D("----------------------------------------------");
+ _print_time("PREV:\t", prev);
+ _print_time("NOW:\t", now);
+
+ if (lap.tv_sec < MIN_LAP_TIME) {
+ lap.tv_sec = 0;
+ lap.tv_nsec = 0;
+ _D ("TOO SHORT LAP");
+ return lap;
+ }
+
+
+ _print_time("LAP:\t", &lap);
+
+ if (lap.tv_nsec < 0) {
+ lap.tv_sec--;
+ lap.tv_nsec = 1e9 + lap.tv_nsec;
+
+ _print_time("LAP_MOD:\t", &lap);
+ }
+ _D("----------------------------------------------");
+
+ return lap;
+}
+
+static inline void _get_lap_time()
+{
+ struct timespec timestamp;
+ int ret = clock_gettime(CLOCK_MONOTONIC, ×tamp);
+ retv_error_message(ret != 0, ret);
+
+ if (s_info.last_timestamp.tv_nsec != 0 || s_info.last_timestamp.tv_sec != 0) {
+ _calculate_lap_time(&s_info.last_timestamp, ×tamp);
+ } else {
+ _D("Starting first lap");
+ }
+
+ s_info.last_timestamp.tv_sec = timestamp.tv_sec;
+ s_info.last_timestamp.tv_nsec = timestamp.tv_nsec;
+}
+
+static void _gpio_interrupted_cb(peripheral_gpio_h gpio, peripheral_error_e error, void *user_data)
+{
+ uint32_t gpio_value = 0;
+ int ret = peripheral_gpio_read(s_info.gpio, &gpio_value);
+ CHECK_GPIO_ERROR(s_info.gpio, ret);
+
+ _D("GPIO_%d value: %d initial: %d, prev: %d", GPIO_PIN, gpio_value, s_info.gpio_initial_value, s_info.gpio_prev_value);
+
+ if (gpio_value != s_info.gpio_initial_value && s_info.gpio_prev_value == s_info.gpio_initial_value) {
+ _get_lap_time();
+ }
+
+
+ s_info.gpio_prev_value = gpio_value;
+}
+
+void resource_lap_counter_init(void)
+{
+ int ret = PERIPHERAL_ERROR_NONE;
+
+ ret = peripheral_gpio_open(GPIO_PIN, &s_info.gpio);
+ retv_error_message(ret != PERIPHERAL_ERROR_NONE, ret);
+
+ ret = peripheral_gpio_set_direction(s_info.gpio, PERIPHERAL_GPIO_DIRECTION_IN);
+ CHECK_GPIO_ERROR(s_info.gpio, ret);
+
+ ret = peripheral_gpio_set_edge_mode(s_info.gpio, PERIPHERAL_GPIO_EDGE_BOTH);
+ CHECK_GPIO_ERROR(s_info.gpio, ret);
+
+ ret = peripheral_gpio_set_interrupted_cb(s_info.gpio, _gpio_interrupted_cb, NULL);
+ CHECK_GPIO_ERROR(s_info.gpio, ret);
+
+ ret = peripheral_gpio_read(s_info.gpio, &s_info.gpio_initial_value);
+ CHECK_GPIO_ERROR(s_info.gpio, ret);
+
+ _D("GPIO_%d initial value: %d", GPIO_PIN, s_info.gpio_initial_value);
+ s_info.gpio_prev_value = s_info.gpio_initial_value;
+}
+
+void resource_lap_counter_destroy(void)
+{
+ peripheral_gpio_unset_interrupted_cb(s_info.gpio);
+ peripheral_gpio_close(s_info.gpio);
+}
+