Skip to content

Commit e2ad016

Browse files
jefdriesenmikeller
authored andcommitted
Use a layout descriptor with a generic decode function
Replace hardcoded constants with a layout descriptor. This reduces the amount of model specific conditions, and makes it easier to add support for new models. The Cressi data format uses nibbles (4 bits) as the smallest unit of storage. Larger values are stored as one or more nibble, typically with a BCD (binary coded decimal) encoding applied. To decode such variable sized numbers, a generic function is added. The offsets in the layout descriptor are also specified in nibbles instead of bytes.
1 parent 3a4afdf commit e2ad016

File tree

1 file changed

+72
-21
lines changed

1 file changed

+72
-21
lines changed

src/cressi_edy_parser.c

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,22 @@
3535

3636
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
3737

38+
typedef struct cressi_edy_layout_t {
39+
unsigned int datetime_y;
40+
unsigned int datetime_md;
41+
unsigned int datetime_hm;
42+
unsigned int avgdepth;
43+
unsigned int maxdepth;
44+
unsigned int temperature;
45+
unsigned int divetime;
46+
unsigned int gasmix;
47+
unsigned int gasmix_count;
48+
} cressi_edy_layout_t;
49+
3850
struct cressi_edy_parser_t {
3951
dc_parser_t base;
4052
unsigned int model;
53+
const cressi_edy_layout_t *layout;
4154
};
4255

4356
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
@@ -56,16 +69,50 @@ static const dc_parser_vtable_t cressi_edy_parser_vtable = {
5669
NULL /* destroy */
5770
};
5871

72+
static const cressi_edy_layout_t edy = {
73+
8, /* datetime_y */
74+
10, /* datetime_md */
75+
28, /* datetime_hm */
76+
1, /* avgdepth */
77+
5, /* maxdepth */
78+
22, /* temperature */
79+
25, /* divetime */
80+
46, 3, /* gasmix */
81+
};
82+
83+
static unsigned int
84+
decode (const unsigned char data[], unsigned int offset, unsigned int n)
85+
{
86+
unsigned int result = 0;
87+
88+
for (unsigned int i = 0; i < n; ++i) {
89+
unsigned char byte = data[offset / 2];
90+
91+
unsigned char nibble = 0;
92+
if ((offset & 1) == 0) {
93+
nibble = (byte >> 4) & 0x0F;
94+
} else {
95+
nibble = byte & 0x0F;
96+
}
97+
98+
result *= 10;
99+
result += nibble;
100+
offset++;
101+
}
102+
103+
return result;
104+
}
59105

60106
static unsigned int
61-
cressi_edy_parser_count_gasmixes (const unsigned char *data)
107+
cressi_edy_parser_count_gasmixes (const unsigned char data[], const cressi_edy_layout_t *layout)
62108
{
63109
// Count the number of active gas mixes. The active gas
64110
// mixes are always first, so we stop counting as soon
65111
// as the first gas marked as disabled is found.
66112
unsigned int i = 0;
67-
while (i < 3) {
68-
if ((data[0x17 - i] & 0xF0) == 0xF0)
113+
while (i < layout->gasmix_count) {
114+
unsigned int state = decode(data, layout->gasmix - i * 2, 1);
115+
if (state == 0x0F)
69116
break;
70117
i++;
71118
}
@@ -89,6 +136,7 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
89136

90137
// Set the default values.
91138
parser->model = model;
139+
parser->layout = &edy;
92140

93141
*out = (dc_parser_t*) parser;
94142

@@ -99,17 +147,19 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
99147
static dc_status_t
100148
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
101149
{
150+
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
151+
const cressi_edy_layout_t *layout = parser->layout;
152+
const unsigned char *data = abstract->data;
153+
102154
if (abstract->size < SZ_HEADER)
103155
return DC_STATUS_DATAFORMAT;
104156

105-
const unsigned char *p = abstract->data;
106-
107157
if (datetime) {
108-
datetime->year = bcd2dec (p[4]) + 2000;
109-
datetime->month = (p[5] & 0xF0) >> 4;
110-
datetime->day = (p[5] & 0x0F) * 10 + ((p[6] & 0xF0) >> 4);
111-
datetime->hour = bcd2dec (p[14]);
112-
datetime->minute = bcd2dec (p[15]);
158+
datetime->year = decode(data, layout->datetime_y, 2) + 2000;
159+
datetime->month = decode(data, layout->datetime_md, 1);
160+
datetime->day = decode(data, layout->datetime_md + 1, 2);
161+
datetime->hour = decode(data, layout->datetime_hm, 2);
162+
datetime->minute = decode(data, layout->datetime_hm + 2, 2);
113163
datetime->second = 0;
114164
datetime->timezone = DC_TIMEZONE_NONE;
115165
}
@@ -122,39 +172,39 @@ static dc_status_t
122172
cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
123173
{
124174
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
175+
const cressi_edy_layout_t *layout = parser->layout;
176+
const unsigned char *data = abstract->data;
125177

126178
if (abstract->size < SZ_HEADER)
127179
return DC_STATUS_DATAFORMAT;
128180

129-
const unsigned char *p = abstract->data;
130-
131181
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
132182

133183
if (value) {
134184
switch (type) {
135185
case DC_FIELD_DIVETIME:
136186
if (parser->model == EDY)
137-
*((unsigned int *) value) = bcd2dec (p[0x0C] & 0x0F) * 60 + bcd2dec (p[0x0D]);
187+
*((unsigned int *) value) = decode(data, layout->divetime, 1) * 60 + decode(data, layout->divetime + 1, 2);
138188
else
139-
*((unsigned int *) value) = (bcd2dec (p[0x0C] & 0x0F) * 100 + bcd2dec (p[0x0D])) * 60;
189+
*((unsigned int *) value) = decode(data, layout->divetime, 3) * 60;
140190
break;
141191
case DC_FIELD_MAXDEPTH:
142-
*((double *) value) = (bcd2dec (p[0x02] & 0x0F) * 100 + bcd2dec (p[0x03])) / 10.0;
192+
*((double *) value) = decode(data, layout->maxdepth, 3) / 10.0;
143193
break;
144194
case DC_FIELD_AVGDEPTH:
145-
*((double *) value) = (bcd2dec (p[0x00] & 0x0F) * 100 + bcd2dec (p[0x01])) / 10.0;
195+
*((double *) value) = decode(data, layout->avgdepth, 3) / 10.0;
146196
break;
147197
case DC_FIELD_GASMIX_COUNT:
148-
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
198+
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(data, layout);
149199
break;
150200
case DC_FIELD_GASMIX:
151201
gasmix->usage = DC_USAGE_NONE;
152202
gasmix->helium = 0.0;
153-
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
203+
gasmix->oxygen = decode(data, layout->gasmix - flags * 2, 2) / 100.0;
154204
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
155205
break;
156206
case DC_FIELD_TEMPERATURE_MINIMUM:
157-
*((double *) value) = (bcd2dec (p[0x0B]) * 10 + ((p[0x0C] & 0xF0) >> 4)) / 10.0;
207+
*((double *) value) = decode(data, layout->temperature, 3) / 10.0;
158208
break;
159209
default:
160210
return DC_STATUS_UNSUPPORTED;
@@ -169,6 +219,7 @@ static dc_status_t
169219
cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
170220
{
171221
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
222+
const cressi_edy_layout_t *layout = parser->layout;
172223

173224
const unsigned char *data = abstract->data;
174225
unsigned int size = abstract->size;
@@ -182,7 +233,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
182233
interval = 15;
183234
}
184235

185-
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data);
236+
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data, layout);
186237
unsigned int gasmix = 0xFFFFFFFF;
187238

188239
unsigned int offset = SZ_HEADER;
@@ -202,7 +253,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
202253
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
203254

204255
// Depth (1/10 m).
205-
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
256+
unsigned int depth = decode(data + offset, 1, 3);
206257
sample.depth = depth / 10.0;
207258
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
208259

0 commit comments

Comments
 (0)