SELKIELogger  1.0.0
DWMessages.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 <math.h>
22 #include <stdint.h>
23 
24 #include "DWMessages.h"
25 #include "DWTypes.h"
26 
31 uint16_t dw_hxv_cycdat(const dw_hxv *in) {
32  return (in->data[0] << 8) + in->data[1];
33 }
34 
39 int16_t dw_hxv_vertical(const dw_hxv *in) {
40  // 12 bits, but stored left aligned in 2 and 3
41  // High byte goes left 4 (left 8 then right 4)
42  // Top nibble of low byte goes right
43  int16_t vert = ((in->data[2] & 0x7F) << 4) + ((in->data[3] & 0xF0) >> 4);
44  if (in->data[2] & 0x80) { vert *= -1; }
45  return vert;
46 }
47 
52 int16_t dw_hxv_north(const dw_hxv *in) {
53  int16_t north = ((in->data[3] & 0x07) << 8) + in->data[4];
54  if (in->data[3] & 0x08) { north *= -1; }
55  return north;
56 }
57 
62 int16_t dw_hxv_west(const dw_hxv *in) {
63  int16_t west = ((in->data[5] & 0x7F) << 4) + ((in->data[6] & 0xF0) >> 4);
64  if (in->data[5] & 0x80) { west *= -1; }
65  return west;
66 }
67 
72 uint16_t dw_hxv_parity(const dw_hxv *in) {
73  return ((in->data[6] & 0x0F) << 8) + in->data[7];
74 }
75 
87 bool dw_spectrum_from_array(const uint16_t *arr, dw_spectrum *out) {
88  if (arr == NULL || out == NULL) { return false; }
89 
90  out->sysseq = (arr[1] & 0xF000) >> 12;
91  out->sysword = (arr[1] & 0x0FFF);
92 
93  if (dw_spectral_block(arr, 0, out) && dw_spectral_block(arr, 1, out) && dw_spectral_block(arr, 2, out) &&
94  dw_spectral_block(arr, 3, out)) {
95  return true;
96  }
97  return false;
98 }
99 
109 bool dw_spectral_block(const uint16_t *arr, const int ix, dw_spectrum *out) {
110  if (ix < 0 || ix > 3) { return false; }
111 
112  out->frequencyBin[ix] = (arr[2 + 4 * ix] & 0x3F00) >> 8;
113  if (out->frequencyBin[ix] > 63) { return false; }
114 
115  if (out->frequencyBin[ix] < 16) {
116  out->frequency[ix] = 0.025 + out->frequencyBin[ix] * 0.005;
117  } else {
118  out->frequency[ix] = 0.11 + out->frequencyBin[ix] * 0.01;
119  }
120  out->direction[ix] = (arr[2 + 4 * ix] & 0x00FF) * 360.0 / 256.0;
121  out->spread[ix] = 0.4476 * (((arr[4 + 4 * ix] & 0xFF00) >> 8) + ((arr[2 + 4 * ix] & 0xC000) >> 14) / 4.0);
122  out->rpsd[ix] = expf(-((float)(arr[3 + 4 * ix] & 0x00FF) / 200.0));
123  out->m2[ix] = ((arr[4 + 4 * ix] & 0x00FF) + ((arr[3 + 4 * ix] & 0xC000) >> 14) / 4.0 - 128);
124  out->m2[ix] /= 128;
125 
126  out->n2[ix] = (((arr[5 + 4 * ix] & 0xFF00) >> 8) + ((arr[3 + 4 * ix] & 0x3000) >> 12) / 4.0 - 128);
127  out->n2[ix] /= 128;
128 
129  out->K[ix] = (arr[5 + 4 * ix] & 0x00FF) / 100.0;
130  return true;
131 }
132 
141 bool dw_system_from_array(const uint16_t *arr, dw_system *out) {
142  if (arr == NULL || out == NULL) { return false; }
143 
144  out->number = (arr[0] & 0x0007) + 1;
145  out->GPSfix = (arr[0] & 0x0010);
146  out->Hrms = (arr[1] & 0x0FFF) / 400.0;
147  out->fzero = (arr[2] & 0x0FFF) / 400.0;
148  out->PSD = 5000 * exp(-(arr[3] & 0x0FFF) / 200.0);
149  out->refTemp = (arr[4] & 0x01FF) / 20.0 - 5;
150  out->waterTemp = (arr[5] & 0x01FF) / 20.0 - 5;
151  out->opTime = (arr[6] & 0x0FF0) >> 4;
152  out->battStatus = (arr[6] & 0x0007);
153  out->a_z_off = (arr[7] & 0x07FF) / 800.0 * ((arr[7] & 0x0800) ? -1 : 1);
154  out->a_x_off = (arr[8] & 0x07FF) / 800.0 * ((arr[8] & 0x0800) ? -1 : 1);
155  out->a_y_off = (arr[9] & 0x07FF) / 800.0 * ((arr[9] & 0x0800) ? -1 : 1);
156  out->lat = ((arr[10] & 0x0800) ? -1 : 1) * 90.0 * ((arr[11] & 0x0FFF) + ((uint32_t)(arr[10] & 0x07FF) << 12)) /
157  (2 << 22);
158  out->lon = ((arr[12] & 0x0800) ? -1 : 1) * 180.0 * ((arr[13] & 0x0FFF) + ((uint32_t)(arr[12] & 0x07FF) << 12)) /
159  (2 << 22);
160  out->orient = (arr[14] & 0x0FF) * 360.0 / 256.0;
161  out->incl = (90.0 / 128.0) * ((arr[15] & 0x00FF) - 128 + ((arr[15] & 0x0F00) >> 8) / 16);
162  return true;
163 }
int16_t dw_hxv_vertical(const dw_hxv *in)
Extract vertical displacement component from HXV input line.
Definition: DWMessages.c:39
bool dw_spectral_block(const uint16_t *arr, const int ix, dw_spectrum *out)
Populate a specific component of dw_spectrum from array of cyclic data words.
Definition: DWMessages.c:109
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_parity(const dw_hxv *in)
Extract parity word from HXV input line.
Definition: DWMessages.c:72
uint16_t dw_hxv_cycdat(const dw_hxv *in)
Extract cyclic data word from HXV input line.
Definition: DWMessages.c:31
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
Internal representation of a Datawell HXV message.
Definition: DWTypes.h:99
uint8_t data[8]
8 bytes of data
Definition: DWTypes.h:102
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
int battStatus
Battery status.
Definition: DWTypes.h:139
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
float PSD
Peak Power Spectral Density.
Definition: DWTypes.h:135
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