nidas  v1.2-1520
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 
116 struct 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 
243 extern int alloc_dsm_circ_buf(struct dsm_sample_circ_buf* c,size_t dlen,int blen);
244 
248 extern void free_dsm_circ_buf(struct dsm_sample_circ_buf* c);
249 
260 extern int realloc_dsm_circ_buf(struct dsm_sample_circ_buf* c,size_t dlen,int blen);
261 
265 extern void init_dsm_circ_buf(struct dsm_sample_circ_buf* c);
266 
280 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
281 typedef struct timespec thiskernel_timespec_t;
282 #else
283 typedef 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  */
290 inline 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  */
302 inline 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  */
322 inline 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 
336 struct sample_read_state
337 {
338  char* samplePtr;
339  unsigned int bytesLeft;
340 };
341 
345 inline int sample_remains(const struct sample_read_state* state)
346 {
347  return state->bytesLeft != 0;
348 }
349 
372 extern ssize_t
373 nidas_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 
377 extern ssize_t
378 nidas_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 
385 struct screen_timetag_data
386 {
390  unsigned int dtTmsec;
391 
396  unsigned int dtUsec;
397 
404  unsigned int nptsCalc;
405 
412  dsm_sample_time_t tt0;
413 
417  int nDt;
418 
422  unsigned int samplesPerDay;
423 
424 #ifdef DO_TIMETAG_ERROR_AVERAGE
425 
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 
456 extern void screen_timetag_init(struct screen_timetag_data* td,
457  int deltaT_Usec, int adjustUsec);
458 
459 extern dsm_sample_time_t screen_timetag(struct screen_timetag_data* td,
460  dsm_sample_time_t tt);
461 
462 #endif /* KERNEL */
463 
464 #endif
#define SECS_PER_DAY
Definition: pc104sg.c:552
void free_dsm_circ_buf(struct dsm_sample_circ_buf *c)
Definition: nidas_util.c:132
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(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
#define TMSECS_PER_SEC
Definition: types.h:135
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
int dsm_sample_time_t
Depending on the module, either tenths of milliseconds, or milliseconds since 00:00 UTC today...
Definition: types.h:48
void init_dsm_circ_buf(struct dsm_sample_circ_buf *c)
Definition: nidas_util.c:155
#define NSECS_PER_TMSEC
Definition: types.h:107
int alloc_dsm_circ_buf(struct dsm_sample_circ_buf *c, size_t dlen, int blen)
Definition: nidas_util.c:62
Definition: types.h:82
int realloc_dsm_circ_buf(struct dsm_sample_circ_buf *c, size_t dlen, int blen)
Definition: nidas_util.c:149
#define NSECS_PER_MSEC
Definition: types.h:102
#define MSECS_PER_SEC
Definition: ublox.cc:58
void screen_timetag_init(struct screen_timetag_data *td, int deltaT_Usec, int adjustUsec)
Definition: nidas_util.c:221