SELKIELogger  1.0.0
DWRead.c
Go to the documentation of this file.
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 <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "SELKIELoggerBase.h"
28 #include "SELKIELoggerDW.h"
29 
30 #include "version.h"
31 
39 #define BUFSIZE 1024
40 
49 int main(int argc, char *argv[]) {
50  program_state state = {0};
51  state.verbose = 1;
52 
53  dw_types inputType = DW_TYPE_UNKNOWN;
54 
55  char *usage = "Usage: %1$s [-v] [-q] [-x] datfile\n"
56  "\t-v\tIncrease verbosity\n"
57  "\t-q\tDecrease verbosity\n"
58  "\t-x\tInput file is in HXV format\n"
59  "\nVersion: " GIT_VERSION_STRING "\n";
60 
61  opterr = 0; // Handle errors ourselves
62  int go = 0;
63  bool doUsage = false;
64  while ((go = getopt(argc, argv, "vqx")) != -1) {
65  switch (go) {
66  case 'v':
67  state.verbose++;
68  break;
69  case 'q':
70  state.verbose--;
71  break;
72  case 'x':
73  inputType = DW_TYPE_HXV;
74  break;
75  case '?':
76  log_error(&state, "Unknown option `-%c'", optopt);
77  doUsage = true;
78  }
79  }
80 
81  // Should be 1 spare arguments: The file to convert
82  if (argc - optind != 1) {
83  log_error(&state, "Invalid arguments");
84  doUsage = true;
85  }
86 
87  if (doUsage) {
88  fprintf(stderr, usage, argv[0]);
89  return -1;
90  }
91 
92  if (inputType == DW_TYPE_UNKNOWN) {
93  log_error(&state, "File type must be specified");
94  return 1;
95  }
96 
97  char *inFileName = strdup(argv[optind]);
98  FILE *inFile = fopen(inFileName, "rb");
99  if (inFile == NULL) {
100  log_error(&state, "Unable to open input file");
101  if (inFileName) { free(inFileName); }
102  return -1;
103  }
104 
105  bool processing = true;
106 
107  char buf[BUFSIZE] = {0};
108  size_t hw = fread(buf, sizeof(char), BUFSIZE, inFile);
109  uint16_t cycdata[20] = {0};
110  uint8_t cycCount = 0;
111 
112  bool sdset[16] = {0};
113  uint16_t sysdata[16] = {0};
114 
115  while (processing || hw > 25) {
116  if (processing && (hw < BUFSIZE)) {
117  ssize_t ret = fread(&(buf[hw]), sizeof(char), BUFSIZE - hw, inFile);
118  if (ret < 1 || feof(inFile)) {
119  processing = false;
120  } else {
121  hw += ret;
122  }
123  }
124 
125  size_t end = hw;
126  dw_hxv tmp = {0};
127  switch (inputType) {
128  case DW_TYPE_HXV:
129  // Read HXV
130  if (dw_string_hxv(buf, &end, &tmp)) {
131  cycdata[cycCount++] = dw_hxv_cycdat(&tmp);
132  fprintf(stdout,
133  "[cyc] Signal: %d, Displacements - N: %+.2f\tW: %+.2f\tV: %+.2f\n",
134  tmp.status, dw_hxv_north(&tmp) / 100.0,
135  dw_hxv_west(&tmp) / 100.0,
136  dw_hxv_vertical(&tmp) / 100.0);
137  }
138  if (cycCount > 18) {
139  bool syncFound = false;
140  for (int i = 0; i < cycCount; ++i) {
141  if (cycdata[i] == 0x7FFF) {
142  syncFound = true;
143  if (i > 0) {
144  // clang-format off
145  for (int j = 0; j < cycCount && (j + i) < 20; ++j) {
146  cycdata[j] = cycdata[j + i];
147  }
148  cycCount = cycCount - i;
149  // clang-format on
150  }
151  break;
152  }
153  }
154  if (!syncFound) {
155  cycCount = 0;
156  memset(cycdata, 0, 20 * sizeof(cycdata[0]));
157  break;
158  }
159 
160  if (cycCount < 16) { break; }
161 
162  dw_spectrum ds = {0};
163  if (!dw_spectrum_from_array(cycdata, &ds)) {
164  fprintf(stderr,
165  "Failed to extract spectrum data\n");
166  } else {
167  sysdata[ds.sysseq] = ds.sysword;
168  sdset[ds.sysseq] = true;
169  fprintf(stdout, "[spe] System data word %d\n",
170  ds.sysseq);
171  fprintf(stdout,
172  "[spe] #\tBin\tFreq\tDir.\tSpread\tM2\tN2\tRPSD\tK\n");
173  for (int n = 0; n < 4; ++n) {
174  fprintf(stdout,
175  "[spe] %1d\t%02d\t%.3f\t%.2f\t%.2f\t%.3f\t%.3f\t%.3f\t%.3f\n",
176  n, ds.frequencyBin[n],
177  ds.frequency[n], ds.direction[n],
178  ds.spread[n], ds.m2[n], ds.n2[n],
179  ds.rpsd[n], ds.K[n]);
180  }
181  fprintf(stdout, "\n");
182  }
183 
184  uint8_t count = 0;
185  for (int i = 0; i < 16; ++i) {
186  if (sdset[i]) {
187  ++count;
188  } else {
189  // First gap found
190  break;
191  }
192  }
193 
194  if (count == 16) {
195  dw_system dsys = {0};
196  // clang-format off
197  if (!dw_system_from_array(sysdata, &dsys)) {
198  fprintf(stderr, "Failed to extract system data\n");
199  } else {
200  fprintf(stdout, "[sys] Transmission number %d\n", dsys.number);
201  fprintf(stdout, "[sys] GPS position %s\n", dsys.GPSfix ? "OK" : "old or invalid");
202  fprintf(stdout, "[sys] RMS Height: %.3f, Fz: %.3f\n", dsys.Hrms, dsys.fzero);
203  fprintf(stdout, "[sys] Ref. Temp: %.1f'C, Water Temp: %.1f'C\n", dsys.refTemp, dsys.waterTemp);
204  fprintf(stdout, "[sys] Expected operational time remaining: %d weeks\n", dsys.opTime);
205  fprintf(stdout, "[sys] Accelerometer offsets: X: %.3f, Y: %.3f, Z: %.3f\n", dsys.a_x_off, dsys.a_y_off, dsys.a_z_off);
206  {
207  int latm = 1;
208  char latc = 'N';
209  int lonm = 1;
210  char lonc = 'E';
211  if (dsys.lat < 0) {
212  latm = -1;
213  latc = 'S';
214  }
215  if (dsys.lon < 0) {
216  lonm = -1;
217  lonc = 'W';
218  }
219  fprintf(stdout,
220  "[sys] Position: %.6f%c %.6f%c, Orientation: %.3f, Inclination: %.3f\n",
221  latm * dsys.lat, latc,
222  lonm * dsys.lon, lonc,
223  dsys.orient, dsys.incl);
224  fprintf(stdout, "\n");
225  }
226  // clang-format on
227  }
228  memset(&sysdata, 0, 16 * sizeof(uint16_t));
229  memset(&sdset, 0, 16 * sizeof(bool));
230  }
231 
232  cycdata[0] = cycdata[18];
233  cycdata[1] = cycdata[19];
234  memset(&(cycdata[2]), 0, 18 * sizeof(uint16_t));
235  cycCount = 2;
236  }
237  break;
238  default:
239  // Error!
240  free(inFileName);
241  return -2;
242  }
243  memmove(buf, &(buf[end]), hw - end);
244  hw -= end;
245  }
246  fclose(inFile);
247  free(inFileName);
248  destroy_program_state(&state);
249  return 0;
250 }
int main(int argc, char *argv[])
Definition: DWRead.c:49
#define BUFSIZE
Allocated buffer size.
Definition: DWRead.c:39
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
dw_types
DW Data format types.
Definition: DWTypes.h:58
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
@ DW_TYPE_UNKNOWN
Default - type not known.
Definition: DWTypes.h:59
void destroy_program_state(program_state *s)
Cleanly destroy program state.
Definition: logging.c:207
void log_error(const program_state *s, const char *format,...)
Output formatted error message.
Definition: logging.c:47
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
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 frequency[4]
Frequency represented by each line.
Definition: DWTypes.h:115
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 a_z_off
Vertical accelerometer offset.
Definition: DWTypes.h:140
float fzero
Zero crossing frequency.
Definition: DWTypes.h:134
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 a_x_off
X-axis accelerometer offset.
Definition: DWTypes.h:141
float refTemp
Reference Temperature.
Definition: DWTypes.h:136
int number
Sequence number.
Definition: DWTypes.h:131
float lat
GPS Latitude.
Definition: DWTypes.h:143
float incl
Buoy inclination.
Definition: DWTypes.h:146
float lon
GPS Longitude.
Definition: DWTypes.h:144
float a_y_off
Y-axis accelerometer offset.
Definition: DWTypes.h:142
int opTime
Weeks of battery life remaining.
Definition: DWTypes.h:138
Program state and logging information.
Definition: logging.h:40
int verbose
Current log verbosity (console output)
Definition: logging.h:43
#define GIT_VERSION_STRING
Git version description.
Definition: version.h.in:13