2 * Copyright (c) 2012 Neratec Solutions AG
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/slab.h>
19 #include "dfs_pattern_detector.h"
20 #include "dfs_pri_detector.h"
23 * struct pri_sequence - sequence of pulses matching one PRI
25 * @pri: pulse repetition interval (PRI) in usecs
26 * @dur: duration of sequence in usecs
27 * @count: number of pulses in this sequence
28 * @count_falses: number of not matching pulses in this sequence
29 * @first_ts: time stamp of first pulse in usecs
30 * @last_ts: time stamp of last pulse in usecs
31 * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
34 struct list_head head
;
45 * struct pulse_elem - elements in pulse queue
46 * @ts: time stamp in usecs
49 struct list_head head
;
54 * pde_get_multiple() - get number of multiples considering a given tolerance
55 * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
57 static u32
pde_get_multiple(u32 val
, u32 fraction
, u32 tolerance
)
66 delta
= (val
< fraction
) ? (fraction
- val
) : (val
- fraction
);
68 if (delta
<= tolerance
)
69 /* val and fraction are within tolerance */
72 factor
= val
/ fraction
;
73 remainder
= val
% fraction
;
74 if (remainder
> tolerance
) {
76 if ((fraction
- remainder
) <= tolerance
)
77 /* remainder is within tolerance */
86 * DOC: Singleton Pulse and Sequence Pools
88 * Instances of pri_sequence and pulse_elem are kept in singleton pools to
89 * reduce the number of dynamic allocations. They are shared between all
90 * instances and grow up to the peak number of simultaneously used objects.
92 * Memory is freed after all references to the pools are released.
94 static u32 singleton_pool_references
;
95 static LIST_HEAD(pulse_pool
);
96 static LIST_HEAD(pseq_pool
);
98 static struct pulse_elem
*pulse_queue_get_tail(struct pri_detector
*pde
)
100 struct list_head
*l
= &pde
->pulses
;
103 return list_entry(l
->prev
, struct pulse_elem
, head
);
106 static bool pulse_queue_dequeue(struct pri_detector
*pde
)
108 struct pulse_elem
*p
= pulse_queue_get_tail(pde
);
110 list_del_init(&p
->head
);
112 /* give it back to pool */
113 list_add(&p
->head
, &pulse_pool
);
115 return (pde
->count
> 0);
118 /* remove pulses older than window */
119 static void pulse_queue_check_window(struct pri_detector
*pde
)
122 struct pulse_elem
*p
;
124 /* there is no delta time with less than 2 pulses */
128 if (pde
->last_ts
<= pde
->window_size
)
131 min_valid_ts
= pde
->last_ts
- pde
->window_size
;
132 while ((p
= pulse_queue_get_tail(pde
)) != NULL
) {
133 if (p
->ts
>= min_valid_ts
)
135 pulse_queue_dequeue(pde
);
139 static bool pulse_queue_enqueue(struct pri_detector
*pde
, u64 ts
)
141 struct pulse_elem
*p
;
142 if (!list_empty(&pulse_pool
)) {
143 p
= list_first_entry(&pulse_pool
, struct pulse_elem
, head
);
146 p
= kmalloc(sizeof(*p
), GFP_KERNEL
);
148 pr_err("failed to allocate pulse_elem\n");
152 INIT_LIST_HEAD(&p
->head
);
154 list_add(&p
->head
, &pde
->pulses
);
157 pulse_queue_check_window(pde
);
158 if (pde
->count
>= pde
->max_count
)
159 pulse_queue_dequeue(pde
);
163 static bool pseq_handler_create_sequences(struct pri_detector
*pde
,
164 u64 ts
, u32 min_count
)
166 struct pulse_elem
*p
;
167 list_for_each_entry(p
, &pde
->pulses
, head
) {
168 struct pri_sequence ps
, *new_ps
;
169 struct pulse_elem
*p2
;
172 u32 delta_ts
= ts
- p
->ts
;
174 if (delta_ts
< pde
->rs
->pri_min
)
175 /* ignore too small pri */
178 if (delta_ts
> pde
->rs
->pri_max
)
179 /* stop on too large pri (sorted list) */
182 /* build a new sequence with new potential pri */
188 ps
.dur
= ps
.pri
* (pde
->rs
->ppb
- 1)
189 + 2 * pde
->rs
->max_pri_tolerance
;
193 min_valid_ts
= ts
- ps
.dur
;
194 /* check which past pulses are candidates for new sequence */
195 list_for_each_entry_continue(p2
, &pde
->pulses
, head
) {
197 if (p2
->ts
< min_valid_ts
)
198 /* stop on crossing window border */
200 /* check if pulse match (multi)PRI */
201 factor
= pde_get_multiple(ps
.last_ts
- p2
->ts
, ps
.pri
,
202 pde
->rs
->max_pri_tolerance
);
205 ps
.first_ts
= p2
->ts
;
207 * on match, add the intermediate falses
210 ps
.count_falses
+= tmp_false_count
;
213 /* this is a potential false one */
217 if (ps
.count
< min_count
)
218 /* did not reach minimum count, drop sequence */
221 /* this is a valid one, add it */
222 ps
.deadline_ts
= ps
.first_ts
+ ps
.dur
;
224 if (!list_empty(&pseq_pool
)) {
225 new_ps
= list_first_entry(&pseq_pool
,
226 struct pri_sequence
, head
);
227 list_del(&new_ps
->head
);
229 new_ps
= kmalloc(sizeof(*new_ps
), GFP_KERNEL
);
233 memcpy(new_ps
, &ps
, sizeof(ps
));
234 INIT_LIST_HEAD(&new_ps
->head
);
235 list_add(&new_ps
->head
, &pde
->sequences
);
240 /* check new ts and add to all matching existing sequences */
242 pseq_handler_add_to_existing_seqs(struct pri_detector
*pde
, u64 ts
)
245 struct pri_sequence
*ps
, *ps2
;
246 list_for_each_entry_safe(ps
, ps2
, &pde
->sequences
, head
) {
250 /* first ensure that sequence is within window */
251 if (ts
> ps
->deadline_ts
) {
252 list_del_init(&ps
->head
);
253 list_add(&ps
->head
, &pseq_pool
);
257 delta_ts
= ts
- ps
->last_ts
;
258 factor
= pde_get_multiple(delta_ts
, ps
->pri
,
259 pde
->rs
->max_pri_tolerance
);
264 if (max_count
< ps
->count
)
265 max_count
= ps
->count
;
273 static struct pri_sequence
*
274 pseq_handler_check_detection(struct pri_detector
*pde
)
276 struct pri_sequence
*ps
;
278 if (list_empty(&pde
->sequences
))
281 list_for_each_entry(ps
, &pde
->sequences
, head
) {
283 * we assume to have enough matching confidence if we
284 * 1) have enough pulses
285 * 2) have more matching than false pulses
287 if ((ps
->count
>= pde
->rs
->ppb_thresh
) &&
288 (ps
->count
* pde
->rs
->num_pri
>= ps
->count_falses
))
295 /* free pulse queue and sequences list and give objects back to pools */
296 static void pri_detector_reset(struct pri_detector
*pde
, u64 ts
)
298 struct pri_sequence
*ps
, *ps0
;
299 struct pulse_elem
*p
, *p0
;
300 list_for_each_entry_safe(ps
, ps0
, &pde
->sequences
, head
) {
301 list_del_init(&ps
->head
);
302 list_add(&ps
->head
, &pseq_pool
);
304 list_for_each_entry_safe(p
, p0
, &pde
->pulses
, head
) {
305 list_del_init(&p
->head
);
306 list_add(&p
->head
, &pulse_pool
);
312 static void pri_detector_exit(struct pri_detector
*de
)
314 pri_detector_reset(de
, 0);
316 singleton_pool_references
--;
317 if (singleton_pool_references
== 0) {
318 /* free singleton pools with no references left */
319 struct pri_sequence
*ps
, *ps0
;
320 struct pulse_elem
*p
, *p0
;
322 list_for_each_entry_safe(p
, p0
, &pulse_pool
, head
) {
326 list_for_each_entry_safe(ps
, ps0
, &pseq_pool
, head
) {
334 static bool pri_detector_add_pulse(struct pri_detector
*de
,
335 struct pulse_event
*event
)
338 struct pri_sequence
*ps
;
340 const struct radar_detector_specs
*rs
= de
->rs
;
342 /* ignore pulses not within width range */
343 if ((rs
->width_min
> event
->width
) || (rs
->width_max
< event
->width
))
346 if ((ts
- de
->last_ts
) < rs
->max_pri_tolerance
)
347 /* if delta to last pulse is too short, don't use this pulse */
351 max_updated_seq
= pseq_handler_add_to_existing_seqs(de
, ts
);
353 if (!pseq_handler_create_sequences(de
, ts
, max_updated_seq
)) {
354 pr_err("failed to create pulse sequences\n");
355 pri_detector_reset(de
, ts
);
359 ps
= pseq_handler_check_detection(de
);
362 pr_info("DFS: radar found: pri=%d, count=%d, count_false=%d\n",
363 ps
->pri
, ps
->count
, ps
->count_falses
);
364 pri_detector_reset(de
, ts
);
367 pulse_queue_enqueue(de
, ts
);
371 struct pri_detector
*
372 pri_detector_init(const struct radar_detector_specs
*rs
)
374 struct pri_detector
*de
;
375 de
= kzalloc(sizeof(*de
), GFP_KERNEL
);
378 de
->exit
= pri_detector_exit
;
379 de
->add_pulse
= pri_detector_add_pulse
;
380 de
->reset
= pri_detector_reset
;
382 INIT_LIST_HEAD(&de
->sequences
);
383 INIT_LIST_HEAD(&de
->pulses
);
384 de
->window_size
= rs
->pri_max
* rs
->ppb
* rs
->num_pri
;
385 de
->max_count
= rs
->ppb
* 2;
388 singleton_pool_references
++;