SELKIELogger  1.0.0
LoggerDW.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "Logger.h"
22 
23 #include "LoggerDW.h"
24 #include "LoggerNet.h"
25 #include "LoggerSignals.h"
26 
27 #include <fcntl.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <sys/socket.h>
32 
33 #include "SELKIELoggerDW.h"
34 
43 void *dw_setup(void *ptargs) {
44  log_thread_args_t *args = (log_thread_args_t *)ptargs;
45 
46  // Delegate connection logic to net_ functions
47  if (!dw_net_connect(ptargs)) {
48  log_error(args->pstate, "[DW:%s] Unable to open a connection", args->tag);
49  args->returnCode = -1;
50  return NULL;
51  }
52 
53  log_info(args->pstate, 2, "[DW:%s] Connected", args->tag);
54  args->returnCode = 0;
55  return NULL;
56 }
57 
65 void *dw_logging(void *ptargs) {
67  log_thread_args_t *args = (log_thread_args_t *)ptargs;
68  dw_params *dwInfo = (dw_params *)args->dParams;
69 
70  log_info(args->pstate, 1, "[DW:%s] Logging thread started", args->tag);
71 
72  const size_t bufSize = 1024;
73  uint8_t *buf = calloc(bufSize, sizeof(uint8_t));
74  int dw_hw = 0;
75  time_t lastRead = time(NULL);
76  time_t lastGoodSignal = time(NULL);
77 
78  uint16_t cycdata[20] = {0};
79  uint8_t cCount = 0;
80 
81  bool sdset[16] = {0};
82  uint16_t sysdata[16] = {0};
83  while (!shutdownFlag) {
84  time_t now = time(NULL);
85  if ((lastRead + dwInfo->timeout) < now) {
86  log_warning(args->pstate, "[DW:%s] Network timeout, reconnecting",
87  args->tag);
88  close(dwInfo->handle);
89  dwInfo->handle = -1;
90  errno = 0;
91  if (net_connect(args)) {
92  log_info(args->pstate, 1, "[DW:%s] Reconnected", args->tag);
93  } else {
94  log_error(args->pstate, "[DW:%s] Unable to reconnect: %s",
95  args->tag, strerror(errno));
96  args->returnCode = -2;
97  pthread_exit(&(args->returnCode));
98  return NULL;
99  }
100  }
101 
102  int ti = 0;
103  if (dw_hw < (ssize_t)(bufSize - 1)) {
104  errno = 0;
105  ti = read(dwInfo->handle, &(buf[dw_hw]), bufSize - dw_hw);
106  if (ti >= 0) {
107  dw_hw += ti;
108  if (ti > 0) {
109  // 0 may not be an error, but could be a dropped
110  // connection if it persists
111  lastRead = now;
112  }
113  } else {
114  if (errno != EAGAIN) {
115  // clang-format off
116  log_error(args->pstate, "[DW:%s] Unexpected error while reading from network (%s)",
117  args->tag, strerror(errno));
118  // clang-format on
119  args->returnCode = -1;
120  pthread_exit(&(args->returnCode));
121  }
122  }
123  }
124 
125  if (dw_hw < 25) {
126  // Sleep briefly, then loop until we have more than the minimum
127  // number of bytes available
128  usleep(5E4);
129  continue;
130  }
132  size_t end = dw_hw;
133  dw_hxv tmp = {0};
134  if (dw_string_hxv((char *)buf, &end, &tmp)) {
135  uint16_t cd = dw_hxv_cycdat(&tmp);
136  // Parse and queue
137  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SIG, tmp.status);
138  if (tmp.status < 2) {
139  lastGoodSignal = now;
140  dw_push_message(args, dwInfo->sourceNum, DWCHAN_DN,
141  dw_hxv_north(&tmp));
142  dw_push_message(args, dwInfo->sourceNum, DWCHAN_DW,
143  dw_hxv_west(&tmp));
144  dw_push_message(args, dwInfo->sourceNum, DWCHAN_DV,
145  dw_hxv_vertical(&tmp));
146  cycdata[cCount++] = cd;
147  }
148  }
149 
150  if ((now - lastGoodSignal) > 300) {
151  log_warning(args->pstate, "[DW:%s] No valid data received from buoy",
152  args->tag);
153  // Reset timer for another 5 minutes
154  lastGoodSignal = now;
155  }
156 
157  if (cCount > 18) {
158  bool syncFound = false;
159  for (int i = 0; i < cCount; ++i) {
160  if (cycdata[i] == 0x7FFF) {
161  syncFound = true;
162  if (i > 0) {
163  for (int j = 0; j < cCount && (j + i) < 20; ++j) {
164  cycdata[j] = cycdata[j + i];
165  }
166  cCount = cCount - i;
167  }
168  break; // End search
169  }
170  }
171  if (!syncFound) {
172  cCount = 0;
173  memset(cycdata, 0, 20 * sizeof(cycdata[0]));
174  continue; // Continue main processing loop
175  }
176 
177  dw_spectrum ds = {0};
178  if (!dw_spectrum_from_array(cycdata, &ds)) {
179  log_info(args->pstate, 1, "[DW:%s] Invalid spectrum data (cCount: %d)\n",
180  args->tag, cCount);
181  } else {
182  sysdata[ds.sysseq] = ds.sysword;
183  sdset[ds.sysseq] = true;
184  // Parse and queue frequency data?
185  if (dwInfo->parseSpectrum) {
186  for (int n = 0; n < 4; ++n) {
187  // clang-format off
188  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPF, ds.frequencyBin[n]);
189  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPD, ds.direction[n]);
190  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPS, ds.spread[n]);
191  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPM, ds.m2[n]);
192  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPN, ds.n2[n]);
193  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPR, ds.rpsd[n]);
194  dw_push_message(args, dwInfo->sourceNum, DWCHAN_SPK, ds.K[n]);
195  // clang-format on
196  }
197  }
198  }
199 
200  uint8_t count = 0;
201  for (int i = 0; i < 16; ++i) {
202  if (sdset[i]) {
203  ++count;
204  } else {
205  // First gap found, no point continuing to count
206  break;
207  }
208  }
209 
210  if (count == 16) {
211  dw_system dsys = {0};
212  if (!dw_system_from_array(sysdata, &dsys)) {
213  log_info(args->pstate, 2, "[DW:%s] Invalid system data\n",
214  args->tag);
215  } else {
216  // Parse system data and queue
217  // clang-format off
218  dw_push_message(args, dwInfo->sourceNum, DWCHAN_LAT, dsys.lat);
219  dw_push_message(args, dwInfo->sourceNum, DWCHAN_LON, dsys.lon);
220  dw_push_message(args, dwInfo->sourceNum, DWCHAN_ORIENT, dsys.orient);
221  dw_push_message(args, dwInfo->sourceNum, DWCHAN_INCLIN, dsys.incl);
222  dw_push_message(args, dwInfo->sourceNum, DWCHAN_GPSFIX, dsys.GPSfix);
223  dw_push_message(args, dwInfo->sourceNum, DWCHAN_HRMS, dsys.Hrms);
224  dw_push_message(args, dwInfo->sourceNum, DWCHAN_TREF, dsys.refTemp);
225  dw_push_message(args, dwInfo->sourceNum, DWCHAN_TWTR, dsys.waterTemp);
226  dw_push_message(args, dwInfo->sourceNum, DWCHAN_WEEKS, dsys.opTime);
227  // clang-format on
228  }
229  memset(&sysdata, 0, 16 * sizeof(uint16_t));
230  memset(&sdset, 0, 16 * sizeof(bool));
231  }
232 
233  cycdata[0] = cycdata[18];
234  cycdata[1] = cycdata[19];
235  memset(&(cycdata[2]), 0, 18 * sizeof(uint16_t));
236  cCount = 2;
237  }
238 
239  msg_t *sm = msg_new_bytes(dwInfo->sourceNum, 3, dw_hw, buf);
240  if (!queue_push(args->logQ, sm)) {
241  log_error(args->pstate, "[DW:%s] Error pushing message to queue",
242  args->tag);
243  msg_destroy(sm);
244  args->returnCode = -1;
245  pthread_exit(&(args->returnCode));
246  }
247  dw_hw = 0;
248  memset(buf, 0, bufSize);
249  }
250  free(buf);
251  pthread_exit(NULL);
252  return NULL; // Superfluous, as returning zero via pthread_exit above
253 }
254 
265 void dw_push_message(log_thread_args_t *args, uint8_t sNum, uint8_t cNum, float data) {
266  msg_t *mm = msg_new_float(sNum, cNum, data);
267  if (mm == NULL) {
268  log_error(args->pstate, "[DW:%s] Unable to allocate message", args->tag);
269  args->returnCode = -1;
270  pthread_exit(&(args->returnCode));
271  }
272  if (!queue_push(args->logQ, mm)) {
273  log_error(args->pstate, "[DW:%s] Error pushing data to queue", args->tag);
274  msg_destroy(mm);
275  args->returnCode = -1;
276  pthread_exit(&(args->returnCode));
277  }
278 }
279 
286 void *dw_shutdown(void *ptargs) {
287  log_thread_args_t *args = (log_thread_args_t *)ptargs;
288  dw_params *dwInfo = (dw_params *)args->dParams;
289  if (dwInfo->handle >= 0) { // Admittedly 0 is unlikely
290  shutdown(dwInfo->handle, SHUT_RDWR);
291  close(dwInfo->handle);
292  }
293  dwInfo->handle = -1;
294  if (dwInfo->addr) {
295  free(dwInfo->addr);
296  dwInfo->addr = NULL;
297  }
298  if (dwInfo->sourceName) {
299  free(dwInfo->sourceName);
300  dwInfo->sourceName = NULL;
301  }
302  return NULL;
303 }
304 
311 bool dw_net_connect(void *ptargs) {
312  log_thread_args_t *args = (log_thread_args_t *)ptargs;
313  dw_params *dwInfo = (dw_params *)args->dParams;
314 
315  if (dwInfo->addr == NULL) {
316  log_error(args->pstate, "[DW:%s] Bad connection details provided", args->tag);
317  return false;
318  }
319 
320  // If we already have an open handle, try and close it
321  if (dwInfo->handle >= 0) { // Admittedly 0 is unlikely
322  shutdown(dwInfo->handle, SHUT_RDWR);
323  close(dwInfo->handle);
324  }
325 
326  dwInfo->handle = -1;
327 
328  struct sockaddr_in targetSA;
329 
330  /* Create the socket. */
331  errno = 0;
332  dwInfo->handle = socket(PF_INET, SOCK_STREAM, 0);
333 
334  struct hostent *hostinfo;
335  targetSA.sin_family = AF_INET;
336  targetSA.sin_port = htons(1180);
337  hostinfo = gethostbyname(dwInfo->addr);
338 
339  if (hostinfo == NULL) {
340  perror("dw_net_connect(hostinfo)");
341  return false;
342  }
343  targetSA.sin_addr = *(struct in_addr *)hostinfo->h_addr;
344 
345  errno = 0;
346  int rs = connect(dwInfo->handle, (struct sockaddr *)&targetSA, sizeof(targetSA));
347  if ((rs < 0) && (errno != EINPROGRESS)) {
348  perror("dw_net_connect(connect)");
349  return false;
350  }
351 
352  // clang-format off
353  if (fcntl(dwInfo->handle, F_SETFL, fcntl(dwInfo->handle, F_GETFL, NULL) | O_NONBLOCK) < 0) {
354  perror("dw_net_connect(fcntl)");
355  return false;
356  }
357  int enable = 1;
358  if (setsockopt(dwInfo->handle, IPPROTO_TCP, TCP_NODELAY, (void *)&enable, sizeof(enable))) {
359  perror("dw_net_connect(NODELAY)");
360  return false;
361  }
362  // clang-format on
363  return true;
364 }
365 
371  .logging = &dw_logging,
372  .shutdown = &dw_shutdown,
373  .channels = &dw_channels};
374  return cb;
375 }
376 
381  dw_params dw = {.addr = NULL,
382  // .port = 1180,
383  .handle = -1,
384  .timeout = 60,
385  .recordRaw = true,
386  .parseSpectrum = false};
387  return dw;
388 }
389 
396 void *dw_channels(void *ptargs) {
397  log_thread_args_t *args = (log_thread_args_t *)ptargs;
398  dw_params *dwInfo = (dw_params *)args->dParams;
399 
400  msg_t *m_sn = msg_new_string(dwInfo->sourceNum, SLCHAN_NAME, strlen(dwInfo->sourceName),
401  dwInfo->sourceName);
402 
403  if (!queue_push(args->logQ, m_sn)) {
404  log_error(args->pstate, "[DW:%s] Error pushing channel name to queue", args->tag);
405  msg_destroy(m_sn);
406  args->returnCode = -1;
407  pthread_exit(&(args->returnCode));
408  }
409 
410  int nChans = 17;
411  if (dwInfo->parseSpectrum) { nChans = 24; }
412 
413  strarray *channels = sa_new(nChans);
414  sa_create_entry(channels, SLCHAN_NAME, 4, "Name");
415  sa_create_entry(channels, SLCHAN_MAP, 8, "Channels");
416  sa_create_entry(channels, SLCHAN_TSTAMP, 9, "Timestamp");
417  sa_create_entry(channels, SLCHAN_RAW, 8, "Raw Data");
418  /*
419  * Cyclic data:
420  */
421  sa_create_entry(channels, DWCHAN_SIG, 6, "Signal");
422  sa_create_entry(channels, DWCHAN_DN, 14, "Displacement N");
423  sa_create_entry(channels, DWCHAN_DW, 14, "Displacement W");
424  sa_create_entry(channels, DWCHAN_DV, 14, "Displacement V");
425  /*
426  * System data:
427  */
428  sa_create_entry(channels, DWCHAN_LAT, 8, "Latitude");
429  sa_create_entry(channels, DWCHAN_LON, 9, "Longitude");
430  sa_create_entry(channels, DWCHAN_ORIENT, 11, "Orientation");
431  sa_create_entry(channels, DWCHAN_INCLIN, 11, "Inclination");
432  sa_create_entry(channels, DWCHAN_GPSFIX, 10, "GPS Status");
433  sa_create_entry(channels, DWCHAN_HRMS, 10, "RMS Height");
434  sa_create_entry(channels, DWCHAN_TREF, 16, "Ref. Temperature");
435  sa_create_entry(channels, DWCHAN_TWTR, 17, "Water Temperature");
436  sa_create_entry(channels, DWCHAN_WEEKS, 15, "Weeks Remaining");
437  /*
438  * Spectral data:
439  */
440  if (dwInfo->parseSpectrum) {
441  sa_create_entry(channels, DWCHAN_SPF, 15, "Sp-FrequencyBin");
442  sa_create_entry(channels, DWCHAN_SPD, 16, "Sp-Direction");
443  sa_create_entry(channels, DWCHAN_SPS, 9, "Sp-Spread");
444  sa_create_entry(channels, DWCHAN_SPM, 5, "Sp-m2");
445  sa_create_entry(channels, DWCHAN_SPN, 5, "Sp-n2");
446  sa_create_entry(channels, DWCHAN_SPR, 7, "Sp-RPSD");
447  sa_create_entry(channels, DWCHAN_SPK, 4, "Sp-K");
448  }
449  msg_t *m_cmap = msg_new_string_array(dwInfo->sourceNum, SLCHAN_MAP, channels);
450 
451  if (!queue_push(args->logQ, m_cmap)) {
452  log_error(args->pstate, "[DW:%s] Error pushing channel map to queue", args->tag);
453  msg_destroy(m_cmap);
454  sa_destroy(channels);
455  free(channels);
456  args->returnCode = -1;
457  pthread_exit(&(args->returnCode));
458  }
459 
460  sa_destroy(channels);
461  free(channels);
462  return NULL;
463 }
464 
471  if (lta->dParams) {
472  log_error(lta->pstate, "[DW:%s] Refusing to reconfigure", lta->tag);
473  return false;
474  }
475 
476  dw_params *dw = calloc(1, sizeof(dw_params));
477  if (!dw) {
478  log_error(lta->pstate, "[DW:%s] Unable to allocate memory for device parameters",
479  lta->tag);
480  return false;
481  }
482  (*dw) = dw_getParams();
483 
484  config_kv *t = NULL;
485  if ((t = config_get_key(s, "host"))) { dw->addr = config_qstrdup(t->value); }
486  t = NULL;
487 
488  if ((t = config_get_key(s, "name"))) {
489  dw->sourceName = config_qstrdup(t->value);
490  } else {
491  // Must set a name, so nick the tag value
492  dw->sourceName = strdup(lta->tag);
493  }
494  t = NULL;
495 
496  if ((t = config_get_key(s, "sourcenum"))) {
497  errno = 0;
498  int sn = strtol(t->value, NULL, 0);
499  if (errno) {
500  log_error(lta->pstate, "[DW:%s] Error parsing source number: %s", lta->tag,
501  strerror(errno));
502  free(dw);
503  return false;
504  }
505  if (sn < 0) {
506  log_error(lta->pstate, "[DW:%s] Invalid source number (%s)", lta->tag,
507  t->value);
508  free(dw);
509  return false;
510  }
511  if (sn < 10) {
512  dw->sourceNum += sn;
513  } else {
514  dw->sourceNum = sn;
515  if (sn < SLSOURCE_EXT || sn > (SLSOURCE_EXT + 0x0F)) {
516  log_warning(
517  lta->pstate,
518  "[DW:%s] Unexpected Source ID number (0x%02x)- this may cause analysis problems",
519  lta->tag, sn);
520  }
521  }
522  }
523 
524  if ((t = config_get_key(s, "timeout"))) {
525  errno = 0;
526  dw->timeout = strtol(t->value, NULL, 0);
527  if (errno) {
528  log_error(lta->pstate, "[DW:%s] Error parsing timeout: %s", lta->tag,
529  strerror(errno));
530  free(dw);
531  return false;
532  }
533 
534  if (dw->timeout <= 0) {
535  log_error(lta->pstate,
536  "[DW:%s] Invalid timeout value (%d is not greater than zero)",
537  lta->tag, dw->timeout);
538  free(dw);
539  return false;
540  }
541  }
542  t = NULL;
543 
544  if ((t = config_get_key(s, "raw"))) {
545  errno = 0;
546  int tmp = config_parse_bool(t->value);
547  if (tmp < 0) {
548  log_error(lta->pstate, "[DW:%s] Invalid value provided for 'raw': %s",
549  lta->tag, t->value);
550  free(dw);
551  return false;
552  }
553  dw->recordRaw = (tmp == 1);
554  }
555  t = NULL;
556 
557  if ((t = config_get_key(s, "spectrum"))) {
558  errno = 0;
559  int tmp = config_parse_bool(t->value);
560  if (tmp < 0) {
561  log_error(lta->pstate, "[DW:%s] Invalid value provided for 'spectrum': %s",
562  lta->tag, t->value);
563  free(dw);
564  return false;
565  }
566  dw->parseSpectrum = (tmp == 1);
567  }
568  t = NULL;
569  lta->dParams = dw;
570  return true;
571 }
int config_parse_bool(const char *b)
Parse string to boolean.
Definition: LoggerConfig.c:240
char * config_qstrdup(const char *c)
Duplicate string, stripping optional leading/trailing quote marks.
Definition: LoggerConfig.c:271
config_kv * config_get_key(const config_section *cs, const char *kn)
Find configugration key within specific section, by name.
Definition: LoggerConfig.c:204
void signalHandlersBlock(void)
Block signals that we have handlers for.
bool shutdown
Set true to start clean shutdown.
Definition: MQTTTest.c:42
msg_t * msg_new_string(const uint8_t source, const uint8_t type, const size_t len, const char *str)
Create a new message with a single string embedded.
Definition: messages.c:84
void msg_destroy(msg_t *msg)
Destroy a message.
Definition: messages.c:349
msg_t * msg_new_string_array(const uint8_t source, const uint8_t type, const strarray *array)
Create a new message containing an array of strings.
Definition: messages.c:116
msg_t * msg_new_bytes(const uint8_t source, const uint8_t type, const size_t len, const uint8_t *bytes)
Create a new message containing raw binary data.
Definition: messages.c:147
msg_t * msg_new_float(const uint8_t source, const uint8_t type, const float val)
Create new message with a single numeric value.
Definition: messages.c:38
int16_t dw_hxv_vertical(const dw_hxv *in)
Extract vertical displacement component from HXV input line.
Definition: DWMessages.c:39
int16_t dw_hxv_west(const dw_hxv *in)
Extract west displacement component from HXV input line.
Definition: DWMessages.c:62
bool dw_spectrum_from_array(const uint16_t *arr, dw_spectrum *out)
Populate dw_spectrum from array of cyclic data words.
Definition: DWMessages.c:87
int16_t dw_hxv_north(const dw_hxv *in)
Extract north displacement component from HXV input line.
Definition: DWMessages.c:52
uint16_t dw_hxv_cycdat(const dw_hxv *in)
Extract cyclic data word from HXV input line.
Definition: DWMessages.c:31
bool dw_string_hxv(const char *in, size_t *end, dw_hxv *out)
Read a line of HXV data from string and convert.
Definition: DWTypes.c:92
bool dw_system_from_array(const uint16_t *arr, dw_system *out)
Extract system data from array of cyclic data words.
Definition: DWMessages.c:141
#define SLCHAN_TSTAMP
Source timestamp (milliseconds, arbitrary epoch)
Definition: sources.h:99
#define SLCHAN_RAW
Raw device data (Not mandatory)
Definition: sources.h:100
#define SLCHAN_MAP
Channel name map (excludes log channels)
Definition: sources.h:98
#define SLCHAN_NAME
Name of source device.
Definition: sources.h:97
#define DWCHAN_DV
Displacement (Vertical)
Definition: LoggerDW.h:64
#define DWCHAN_TWTR
Water Temperature.
Definition: LoggerDW.h:73
#define DWCHAN_SPM
Spectral data: M2 coefficient.
Definition: LoggerDW.h:79
#define DWCHAN_DN
Displacement (North)
Definition: LoggerDW.h:62
#define DWCHAN_SPS
Spectral data: Spread.
Definition: LoggerDW.h:78
#define DWCHAN_LON
Longitude (Decimal degrees)
Definition: LoggerDW.h:67
#define DWCHAN_SPD
Spectral data: Direction.
Definition: LoggerDW.h:77
#define DWCHAN_SIG
Reported signal strength.
Definition: LoggerDW.h:61
#define DWCHAN_LAT
Latitude (Decimal degrees)
Definition: LoggerDW.h:66
#define DWCHAN_GPSFIX
GPS quality.
Definition: LoggerDW.h:70
#define DWCHAN_DW
Displacement (West)
Definition: LoggerDW.h:63
#define DWCHAN_INCLIN
Device inclination.
Definition: LoggerDW.h:69
#define DWCHAN_SPF
Spectral data: Frequency.
Definition: LoggerDW.h:76
#define DWCHAN_SPK
Spectral data: K factor.
Definition: LoggerDW.h:82
#define DWCHAN_SPN
Spectral data: N2 coefficient.
Definition: LoggerDW.h:80
#define DWCHAN_ORIENT
Device orientation.
Definition: LoggerDW.h:68
#define DWCHAN_SPR
Spectral data: Relative PSD.
Definition: LoggerDW.h:81
#define DWCHAN_HRMS
RMS Wave Height.
Definition: LoggerDW.h:71
#define DWCHAN_TREF
Reference Temperature.
Definition: LoggerDW.h:72
#define DWCHAN_WEEKS
Estimated weeks of battery remaining.
Definition: LoggerDW.h:74
bool dw_net_connect(void *ptargs)
DW Network connection helper.
Definition: LoggerDW.c:311
void * dw_channels(void *ptargs)
Channel map.
Definition: LoggerDW.c:396
bool dw_parseConfig(log_thread_args_t *lta, config_section *s)
Take a configuration section and parse parameters.
Definition: LoggerDW.c:470
void dw_push_message(log_thread_args_t *args, uint8_t sNum, uint8_t cNum, float data)
Create and push messages to queue.
Definition: LoggerDW.c:265
void * dw_setup(void *ptargs)
Datawell thread setup.
Definition: LoggerDW.c:43
dw_params dw_getParams()
Fill out default MP source parameters.
Definition: LoggerDW.c:380
void * dw_logging(void *ptargs)
Datawell source main logging loop.
Definition: LoggerDW.c:65
void * dw_shutdown(void *ptargs)
Datawell source shutdown.
Definition: LoggerDW.c:286
device_callbacks dw_getCallbacks()
Fill out device callback functions for logging.
Definition: LoggerDW.c:369
bool net_connect(void *ptargs)
Network connection helper function.
Definition: LoggerNet.c:176
#define SLSOURCE_EXT
External data sources recorded but not interpreted by the logger.
Definition: sources.h:71
atomic_bool shutdownFlag
Trigger clean software shutdown.
Definition: LoggerSignals.c:34
void log_info(const program_state *s, const int level, const char *format,...)
Output formatted information message at a given level.
Definition: logging.c:125
void log_warning(const program_state *s, const char *format,...)
Output formatted warning message.
Definition: logging.c:86
void log_error(const program_state *s, const char *format,...)
Output formatted error message.
Definition: logging.c:47
bool queue_push(msgqueue *queue, msg_t *msg)
Add a message to the tail of the queue.
Definition: queue.c:103
void sa_destroy(strarray *sa)
Destroy array and contents.
Definition: strarray.c:182
strarray * sa_new(int entries)
Allocate storage for a new array.
Definition: strarray.c:37
bool sa_create_entry(strarray *array, const int index, const size_t len, const char *src)
Create an string in a given position from a character array and length.
Definition: strarray.c:149
Represent a key=value pair.
Definition: LoggerConfig.h:42
char * value
Configuration item value.
Definition: LoggerConfig.h:44
Configuration file section.
Definition: LoggerConfig.h:54
Device specific function information.
Definition: Logger.h.in:72
device_fn startup
Called serially at startup, opens devices etc.
Definition: Logger.h.in:73
Internal representation of a Datawell HXV message.
Definition: DWTypes.h:99
uint8_t status
Error count. 0 or 1 OK, 2+ error.
Definition: DWTypes.h:100
Configuration is as per simple network sources.
Definition: LoggerDW.h:42
char * sourceName
User defined name for this source.
Definition: LoggerDW.h:43
bool parseSpectrum
Enable parsing of spectral data.
Definition: LoggerDW.h:49
int timeout
Reconnect if no data received after this interval [s].
Definition: LoggerDW.h:47
uint8_t sourceNum
Source ID for messages.
Definition: LoggerDW.h:44
int handle
Handle for currently opened device.
Definition: LoggerDW.h:46
char * addr
Target name.
Definition: LoggerDW.h:45
bool recordRaw
Enable retention of raw data.
Definition: LoggerDW.h:48
Internal representation of HXV spectral messages.
Definition: DWTypes.h:111
uint8_t frequencyBin[4]
Index for each line of spectral data.
Definition: DWTypes.h:114
float m2[4]
M2 Fourier coefficient for each line.
Definition: DWTypes.h:119
uint16_t sysword
12 bits of system data
Definition: DWTypes.h:113
float rpsd[4]
Relative power spectral density for each line.
Definition: DWTypes.h:118
float K[4]
Check factor for each line.
Definition: DWTypes.h:121
uint8_t sysseq
System data sequence number.
Definition: DWTypes.h:112
float spread[4]
Wave spread for each line.
Definition: DWTypes.h:116
float direction[4]
Direction for each line.
Definition: DWTypes.h:117
float n2[4]
N2 Fourier coefficient for each line.
Definition: DWTypes.h:120
Internal representation of HXV system messages.
Definition: DWTypes.h:130
float Hrms
RMS Wave height.
Definition: DWTypes.h:133
bool GPSfix
Valid GPS fix available.
Definition: DWTypes.h:132
float waterTemp
Water Temperature.
Definition: DWTypes.h:137
float orient
Buoy orientation.
Definition: DWTypes.h:145
float refTemp
Reference Temperature.
Definition: DWTypes.h:136
float lat
GPS Latitude.
Definition: DWTypes.h:143
float incl
Buoy inclination.
Definition: DWTypes.h:146
float lon
GPS Longitude.
Definition: DWTypes.h:144
int opTime
Weeks of battery life remaining.
Definition: DWTypes.h:138
Logging thread information.
Definition: Logger.h.in:86
msgqueue * logQ
Main message queue. Pushed to by threads, consumed by main()
Definition: Logger.h.in:89
char * tag
Tag/source name for messages etc.
Definition: Logger.h.in:87
void * dParams
Device/Thread specific data.
Definition: Logger.h.in:92
program_state * pstate
Current program state, used for logging.
Definition: Logger.h.in:90
int returnCode
Thread return code (output)
Definition: Logger.h.in:93
Queuable message.
Definition: messages.h:71
Array of strings.
Definition: strarray.h:43