1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 /**
10 * @file pedometer.c
11 * @brief The pedometer.c file contains the interface definitions for
12 * pedometer application.
13 */
14
15 /*******************************************************************************
16 * Includes
17 ******************************************************************************/
18 #include "pedometer.h"
19
20 /*******************************************************************************
21 * Macros, globals
22 ******************************************************************************/
23 #define PEDOMETER_STATUS_ACTIVITY_BITNUM 0
24 #define PEDOMETER_STATUS_SUSPEND_BITNUM 3
25 #define PEDOMETER_STATUS_ACTCHG_BITNUM 4
26 #define PEDOMETER_STATUS_STEPCHG_BITNUM 5
27 #define PEDOMETER_STATUS_SUSPCHG_BITNUM 6
28 #define PEDOMETER_STATUS_MRGFLG_BITNUM 7
29
30 #define PEDOMETER_STATUS_ACTIVITY_MASK (7 << PEDOMETER_STATUS_ACTIVITY_BITNUM)
31 #define PEDOMETER_STATUS_SUSPEND_MASK (1 << PEDOMETER_STATUS_SUSPEND_BITNUM)
32 #define PEDOMETER_STATUS_ACTCHG_MASK (1 << PEDOMETER_STATUS_ACTCHG_BITNUM)
33 #define PEDOMETER_STATUS_STEPCHG_MASK (1 << PEDOMETER_STATUS_STEPCHG_BITNUM)
34 #define PEDOMETER_STATUS_SUSPCHG_MASK (1 << PEDOMETER_STATUS_SUSPCHG_BITNUM)
35 #define PEDOMETER_STATUS_MRGFLG_MASK (1 << PEDOMETER_STATUS_MRGFLG_BITNUM)
36
37 #define PEDOMETER_STATUS_CHG_MASK \
38 (PEDOMETER_STATUS_ACTCHG_MASK | PEDOMETER_STATUS_STEPCHG_MASK | PEDOMETER_STATUS_SUSPCHG_MASK)
39 #define SQUARED(x) ((x) * (x))
40 /* below values are the best set of value for the algorthm and computed during the algorithm definition.*/
41 /******************************************************************************
42 * Private Function Declarations
43 *****************************************************************************/
44
45 /* Update status variables */
46 static void status_update(pedometer_t *pedometer, uint32_t events, bool suspend);
47
48 /* Determine autonomous suspend state */
49 static bool suspend_compute(pedometer_t *pPedometer, ped_accel_t *pData);
50
51 /* compute the debounce. */
52 static bool debounce_count(bool dbcntm, bool condition, debounce_count_t *count, debounce_count_t threshold);
53
54 /* Cast uint32_t to uint16_t with saturate */
55 static uint16_t uint32_to_uint16(uint32_t val);
56
57 /******************************************************************************
58 * Private Variable Definitions
59 ******************************************************************************/
60
61 static const pedometer_t pedometer_default = {.status =
62 {
63 .version = 2,
64 },
65 .config = {
66 .sleepcount_threshold = 1,
67 .bits = {.config = 1},
68 .keynetik =
69 {
70 .height = 175,
71 .weight = 80,
72 .filtersteps = PEDO_FILTER_STEPS_DEFAULT,
73 .bits =
74 {
75 .filtertime = PEDO_FILTER_TIME_DEFAULT,
76 },
77 .speedperiod = PEDO_SPEED_PERIOD_DEFAULT,
78 .stepthreshold = PEDO_STEP_THRESHOLD_DEFAULT,
79 },
80 .stepcoalesce = 1,
81 .oneG = PEDO_ONEG_8G,
82 .frequency = PEDO_FREQHZ_DEFAULT,
83 }};
84
85 /*******************************************************************************
86 * Code
87 ******************************************************************************/
88
89 /*
90 ** ===================================================================
91 ** Method : pedometer_init
92 ** brief : The interface function initialize the pedometer.
93 ** params[in] : pedometer_t *pPedometer, handle to the pedometer.
94 **
95 ** ===================================================================
96 */
pedometer_init(pedometer_t * pPedometer)97 void pedometer_init(pedometer_t *pPedometer)
98 {
99 *pPedometer = pedometer_default;
100 KeynetikInitialize(pPedometer->config.oneG, pPedometer->config.frequency, &pPedometer->config.keynetik);
101 pPedometer->private.stepchg_stepcount = 0;
102 }
103
104 /*** ===================================================================
105 ** Method : pedometer_configure
106 ** brief : The interface function to configure the pedometer
107 ** params[in] : pedometer_t *pPedometer, handle to the pedometer.
108 ** params[in] : pedometer_config_t configuration parameter.
109 ** ===================================================================
110 */
pedometer_configure(pedometer_t * pPedometer,const pedometer_config_t * pConfig)111 void pedometer_configure(pedometer_t *pPedometer, const pedometer_config_t *pConfig)
112 {
113 pPedometer->config = *pConfig;
114 KeynetikInitialize(pPedometer->config.oneG, pPedometer->config.frequency, &pPedometer->config.keynetik);
115 pPedometer->private.stepchg_stepcount = 0;
116 }
117 /*
118 ** ===================================================================
119 ** Method : pedometer_run
120 ** brief : The interface function excutes the pedometer algorithm.
121 ** params[in] : pedometer_t *pPedometer, handle to the pedometer.
122 ** params[in] : ped_accel_t data acceleration data.
123 ** ===================================================================
124 */
pedometer_run(pedometer_t * pPedometer,ped_accel_t * pData)125 int32_t pedometer_run(pedometer_t *pPedometer, ped_accel_t *pData)
126 {
127 uint32_t events = 0;
128 /* if suspend, don't execute the alogrithm and save the power.*/
129 bool suspend = suspend_compute(pPedometer, pData);
130 if (!suspend)
131 {
132 events = KeynetikHandleIncomingEvent(pData->accel[0], pData->accel[1], pData->accel[2]);
133 }
134 status_update(pPedometer, events, suspend);
135 return events;
136 }
137 /*
138 ** ===================================================================
139 ** Method : status_update
140 ** brief : update the status of the pedometer output
141 ** params[in] : pedometer_t *pPedometer, handle to the pedometer.
142 ** params[in] : uint32_t events kynetic event
143 ** params[in] : bool suspend suspend flag
144 ** ===================================================================
145 */
status_update(pedometer_t * pPedometer,uint32_t events,bool suspend)146 static void status_update(pedometer_t *pPedometer, uint32_t events, bool suspend)
147 {
148 bool activity_stable =
149 debounce_count(pPedometer->config.bits.activity_dbcntm, !(events & KEYNETIK_ACTIVITYCHANGED),
150 &pPedometer->private.activitycount, pPedometer->config.activitycount_threshold);
151
152 activitylevel_t activity = activity_stable ? keynetikActivityLevel : pPedometer->status.status.bits.activity;
153 uint16_t stepcount = uint32_to_uint16(keynetikStepCount);
154 uint8_t newstatus = (activity << PEDOMETER_STATUS_ACTIVITY_BITNUM) & PEDOMETER_STATUS_ACTIVITY_MASK;
155
156 if ((newstatus ^ pPedometer->status.status.byte) & PEDOMETER_STATUS_ACTIVITY_MASK)
157 newstatus |= PEDOMETER_STATUS_ACTCHG_MASK;
158
159 if (pPedometer->config.stepcoalesce &&
160 (stepcount - pPedometer->private.stepchg_stepcount >= pPedometer->config.stepcoalesce))
161 {
162 pPedometer->private.stepchg_stepcount = stepcount;
163 newstatus |= PEDOMETER_STATUS_STEPCHG_MASK;
164 }
165
166 if (suspend)
167 newstatus |= PEDOMETER_STATUS_SUSPEND_MASK;
168
169 if ((newstatus ^ pPedometer->status.status.byte) & PEDOMETER_STATUS_SUSPEND_MASK)
170 newstatus |= PEDOMETER_STATUS_SUSPCHG_MASK;
171
172 if (newstatus & PEDOMETER_STATUS_CHG_MASK)
173 newstatus |= PEDOMETER_STATUS_MRGFLG_MASK;
174 /* Update the status such stepcount, distance, speed etc..*/
175 pPedometer->status.stepcount = uint32_to_uint16(keynetikStepCount);
176 pPedometer->status.distance = uint32_to_uint16(keynetikDistance);
177 pPedometer->status.speed = keynetikSpeed;
178 pPedometer->status.calories = uint32_to_uint16(keynetikCalories);
179 pPedometer->status.status.byte = newstatus;
180 }
181 /*
182 ** ===================================================================
183 ** Method : suspend_compute
184 ** brief : compute the suspend status.
185 ** params[in] : pedometer_t *pPedometer, handle to the pedometer.
186 ** params[in] : ped_accel_t data acceleration data.
187 ** ===================================================================
188 */
suspend_compute(pedometer_t * pPedometer,ped_accel_t * pData)189 static bool suspend_compute(pedometer_t *pPedometer, ped_accel_t *pData)
190 {
191 /* compute the magnitude*/
192 uint32_t mag2 = SQUARED(pData->accel[0]) + SQUARED(pData->accel[1]) + SQUARED(pData->accel[2]);
193 bool stationary =
194 (mag2 > SQUARED(pPedometer->config.sleepminimum)) && (mag2 < SQUARED(pPedometer->config.sleepmaximum));
195 bool suspend = debounce_count(pPedometer->config.bits.sleep_dbcntm, stationary, &pPedometer->status.sleepcount,
196 pPedometer->config.sleepcount_threshold);
197 return (suspend);
198 }
199 /*
200 ** ===================================================================
201 ** Method : uint32_to_uint16
202 ** brief : conversion function from 32 to 16.
203 ** params[in] : uint32_t x, imput
204 ** params[in] : ped_accel_data data acceleration data.
205 ** ===================================================================
206 */
uint32_to_uint16(uint32_t val)207 uint16_t uint32_to_uint16(uint32_t val)
208 {
209 if (val > 0x0000FFFF)
210 return (0xFFFF);
211 return ((uint16_t)val);
212 }
213 /*
214 ** ===================================================================
215 ** Method : debounce_count
216 ** brief : compute the debouct status.
217 ** params[in] : bool dbcntm,
218 ** params[in] : bool condition
219 ** params[in] : debounce_count_t *count,
220 ** params[in] : debounce_count_t threshold, debouce threshold
221 ** ===================================================================
222 */
debounce_count(bool dbcntm,bool condition,debounce_count_t * count,debounce_count_t threshold)223 static bool debounce_count(bool dbcntm, bool condition, debounce_count_t *count, debounce_count_t threshold)
224 {
225 if (condition)
226 {
227 /* increment count up to, but not above the threshold */
228 *count = (*count + 1) < threshold ? *count + 1 : threshold;
229 }
230 else
231 {
232 if (dbcntm)
233 *count = 0;
234 else
235 /* decrement count down to, but not below zero */
236 *count = (*count - 1) > 0 ? *count - 1 : 0;
237 }
238 return ((bool)(*count >= threshold));
239 }
240