nidas v1.2.3
util.h
Go to the documentation of this file.
1/* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8; -*- */
2/* vim: set shiftwidth=8 softtabstop=8 expandtab: */
3/*
4 ********************************************************************
5 ** NIDAS: NCAR In-situ Data Acquistion Software
6 **
7 ** 2007, Copyright University Corporation for Atmospheric Research
8 **
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 2 of the License, or
12 ** (at your option) any later version.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
18 **
19 ** The LICENSE.txt file accompanying this software contains
20 ** a copy of the GNU General Public License. If it is not found,
21 ** write to the Free Software Foundation, Inc.,
22 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 **
24 ********************************************************************
25*/
26/*
27 Utility functions for nidas device drivers.
28
29 Original Author: Gordon Maclean
30
31*/
32
33#ifndef NIDAS_LINUX_NIDAS_UTIL_H
34#define NIDAS_LINUX_NIDAS_UTIL_H
35
36#if defined(__KERNEL__)
37
38#include "types.h"
39#include <linux/types.h>
40#include <linux/wait.h>
41#include <linux/fs.h>
42
43#include <linux/circ_buf.h>
44#include <linux/ktime.h>
45#include <linux/version.h>
46
77/*
78 * https://elixir.bootlin.com/linux/latest/source is a useful site for searching
79 * through kernel versions for an indentifier.
80 *
81 * Vulcans are running 2.6.21 kernel, ACCESS_ONCE and READ_ONCE are not defined
82 * Vipers/titans: 3.16.0, ACCESS_ONCE is defined, but READ_ONCE is not
83 * 3.18.13: first appearance of READ_ONCE
84 */
85#ifndef READ_ONCE
86#ifdef ACCESS_ONCE
87#define READ_ONCE(x) ACCESS_ONCE(x)
88#else
89/* def of ACCESS_ONCE in include/linux/compiler.h in 3.16 */
90#define READ_ONCE(x) (*(volatile typeof(x) *)&(x))
91#endif
92#endif
93
94#ifndef WRITE_ONCE
95#ifdef ACCESS_ONCE
96#define WRITE_ONCE(x,val) ACCESS_ONCE(x) = (val)
97#else
98#define WRITE_ONCE(x,val) (*(volatile typeof(x) *)&(x)) = (val)
99#endif
100#endif
101
116struct dsm_sample_circ_buf {
117 struct dsm_sample **buf;
118 int head;
119 int tail;
120 int size;
121 void** pages;
122 int npages;
123};
124
138#define GET_HEAD(cbuf,size) \
139 ({\
140 (CIRC_SPACE((cbuf).head,READ_ONCE((cbuf).tail),(size)) > 0 ? \
141 (cbuf).buf[(cbuf).head] : 0);\
142 })
143
152#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
153#define INCREMENT_HEAD(cbuf,size) \
154 smp_store_release(&(cbuf).head, ((cbuf).head + 1) & ((size) - 1))
155#else
156#define INCREMENT_HEAD(cbuf,size) \
157 do { smp_wmb(); (cbuf).head = ((cbuf).head + 1) & ((size) - 1); } while (0)
158#endif
159
160#define NEXT_HEAD(cbuf,size) \
161 (INCREMENT_HEAD(cbuf,size), GET_HEAD(cbuf,size))
162
190#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
191#define GET_TAIL(cbuf,size) \
192 ({\
193 int tmp = CIRC_CNT(smp_load_acquire(&(cbuf).head),(cbuf).tail,size);\
194 (tmp > 0 ? (cbuf).buf[(cbuf).tail] : 0);\
195 })
196#else
197#define GET_TAIL(cbuf,size) \
198 ({\
199 int tmp = CIRC_CNT(READ_ONCE((cbuf).head),(cbuf).tail,size);\
200 smp_read_barrier_depends();\
201 (tmp > 0 ? (cbuf).buf[(cbuf).tail] : 0);\
202 })
203#endif
204
215#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
216#define INCREMENT_TAIL(cbuf,size) \
217 smp_store_release(&(cbuf).tail, ((cbuf).tail + 1) & ((size) - 1))
218
219#else
220#define INCREMENT_TAIL(cbuf,size) \
221 do { smp_mb(); (cbuf).tail = ((cbuf).tail + 1) & ((size) - 1); } while(0)
222#endif
223
227#define EMPTY_CIRC_BUF(cbuf) \
228 do { (cbuf).tail = (cbuf).head = 0; smp_mb(); } while(0)
229
243extern int alloc_dsm_circ_buf(struct dsm_sample_circ_buf* c,size_t dlen,int blen);
244
248extern void free_dsm_circ_buf(struct dsm_sample_circ_buf* c);
249
260extern int realloc_dsm_circ_buf(struct dsm_sample_circ_buf* c,size_t dlen,int blen);
261
265extern void init_dsm_circ_buf(struct dsm_sample_circ_buf* c);
266
280#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
281typedef struct timespec thiskernel_timespec_t;
282#else
283typedef struct timespec64 thiskernel_timespec_t;
284#endif
285
286/*
287 * Return system time in a thiskernel_timespec_t.
288 * ktime_get_real_ts64 first appears in 3.17
289 */
290inline void getSystemTimeTs(thiskernel_timespec_t *ts)
291{
292#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
293 ktime_get_real_ts(ts);
294#else
295 ktime_get_real_ts64(ts);
296#endif
297}
298
299/*
300 * Return time in milliseconds since 00:00 UTC.
301 */
302inline dsm_sample_time_t getSystemTimeMsecs(void)
303{
304 thiskernel_timespec_t ts;
305 getSystemTimeTs(&ts);
306 /* BITS_PER_LONG seems to be defined in all kernels, but
307 * __BITS_PER_LONG isn't defined in 2.6 kernels.
308 * Use __BITS_PER_LONG if exporting a .h to user space. */
309#if BITS_PER_LONG == 32 && LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
310 /* do_div changes dividend in place, returns remainder */
311 return do_div(ts.tv_sec, SECS_PER_DAY) * MSECS_PER_SEC +
312 ts.tv_nsec / NSECS_PER_MSEC;
313#else
314 return (ts.tv_sec % SECS_PER_DAY) * MSECS_PER_SEC +
315 ts.tv_nsec / NSECS_PER_MSEC;
316#endif
317}
318
319/*
320 * Return time in tenths of milliseconds since 00:00 UTC.
321 */
322inline dsm_sample_time_t getSystemTimeTMsecs(void)
323{
324 thiskernel_timespec_t ts;
325 getSystemTimeTs(&ts);
326#if BITS_PER_LONG == 32 && LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
327 /* do_div changes dividend in place, returns remainder */
328 return do_div(ts.tv_sec, SECS_PER_DAY) * TMSECS_PER_SEC +
329 ts.tv_nsec / NSECS_PER_TMSEC;
330#else
331 return (ts.tv_sec % SECS_PER_DAY) * TMSECS_PER_SEC +
332 ts.tv_nsec / NSECS_PER_TMSEC;
333#endif
334}
335
336struct sample_read_state
337{
338 char* samplePtr;
339 unsigned int bytesLeft;
340};
341
345inline int sample_remains(const struct sample_read_state* state)
346{
347 return state->bytesLeft != 0;
348}
349
372extern ssize_t
373nidas_circbuf_read(struct file *filp, char __user* buf, size_t count,
374 struct dsm_sample_circ_buf* cbuf, struct sample_read_state* state,
375 wait_queue_head_t* readq);
376
377extern ssize_t
378nidas_circbuf_read_nowait(struct file *filp, char __user* buf, size_t count,
379 struct dsm_sample_circ_buf* cbuf, struct sample_read_state* state);
380
385struct screen_timetag_data
386{
390 unsigned int dtTmsec;
391
396 unsigned int dtUsec;
397
404 unsigned int nptsCalc;
405
413
417 int nDt;
418
422 unsigned int samplesPerDay;
423
424#ifdef DO_TIMETAG_ERROR_AVERAGE
428 int nSum;
429
433 int errAvg;
434#else
435
439 int nmin;
440
444 int nptsMin;
445
449 int tdiffmin;
450
451#endif
452
453
454};
455
456extern void screen_timetag_init(struct screen_timetag_data* td,
457 int deltaT_Usec, int adjustUsec);
458
459extern dsm_sample_time_t screen_timetag(struct screen_timetag_data* td,
461
462#endif /* KERNEL */
463
464#endif
void init_dsm_circ_buf(struct dsm_sample_circ_buf *c)
Definition nidas_util.c:155
int alloc_dsm_circ_buf(struct dsm_sample_circ_buf *c, size_t dlen, int blen)
Definition nidas_util.c:62
void free_dsm_circ_buf(struct dsm_sample_circ_buf *c)
Definition nidas_util.c:132
int realloc_dsm_circ_buf(struct dsm_sample_circ_buf *c, size_t dlen, int blen)
Definition nidas_util.c:149
void screen_timetag_init(struct screen_timetag_data *td, int deltaT_Usec, int adjustUsec)
Definition nidas_util.c:221
ssize_t nidas_circbuf_read(struct file *filp, char __user *buf, size_t count, struct dsm_sample_circ_buf *cbuf, struct sample_read_state *state, wait_queue_head_t *readq)
Definition nidas_util.c:196
dsm_sample_time_t screen_timetag(struct screen_timetag_data *td, dsm_sample_time_t tt)
Adjust time tags in a series which should have a fixed delta-T, such as from an A2D.
Definition nidas_util.c:260
ssize_t nidas_circbuf_read_nowait(struct file *filp, char __user *buf, size_t count, struct dsm_sample_circ_buf *cbuf, struct sample_read_state *state)
Definition nidas_util.c:162
#define SECS_PER_DAY
Definition pc104sg.c:552
Definition types.h:82
#define NSECS_PER_MSEC
Definition types.h:102
#define NSECS_PER_TMSEC
Definition types.h:107
int dsm_sample_time_t
Depending on the module, either tenths of milliseconds, or milliseconds since 00:00 UTC today.
Definition types.h:48
#define TMSECS_PER_SEC
Definition types.h:135
#define MSECS_PER_SEC
Definition ublox.cc:58