Skip to content

Commit 6dbb648

Browse files
jefdriesenmikeller
authored andcommitted
Add support for the Seac Tablet
The Seac Tablet uses almost the same protocol as the Seac Screen and Action, but with a few small differences: - A slightly different set of commands, but with exactly the same functionality. - The new variant of the READ command does no longer pad the response packet to 2048 bytes. - The profile area starts at address 0x0A0000 instead of 0x010000. The Seac Tablet also support tank pressure transmitters.
1 parent 9d8a318 commit 6dbb648

File tree

7 files changed

+112
-32
lines changed

7 files changed

+112
-32
lines changed

src/descriptor.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ static const dc_descriptor_t g_descriptors[] = {
484484
/* Seac Screen */
485485
{"Seac", "Action", DC_FAMILY_SEAC_SCREEN, 0x01, DC_TRANSPORT_SERIAL, NULL},
486486
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0x02, DC_TRANSPORT_SERIAL, NULL},
487+
{"Seac", "Tablet", DC_FAMILY_SEAC_SCREEN, 0x10, DC_TRANSPORT_SERIAL, NULL},
487488
/* Deepblu Cosmiq */
488489
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
489490
/* Oceans S1 */

src/halcyon_symbios_parser.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ typedef struct halcyon_symbios_tank_t {
8080
unsigned int beginpressure;
8181
unsigned int endpressure;
8282
unsigned int gasmix;
83-
dc_usage_t usage;
83+
dc_tank_usage_t usage;
8484
} halcyon_symbios_tank_t;
8585

8686
typedef struct halcyon_symbios_parser_t {
@@ -156,7 +156,7 @@ halcyon_symbios_parser_create (dc_parser_t **out, dc_context_t *context, const u
156156
parser->tank[i].beginpressure = 0;
157157
parser->tank[i].endpressure = 0;
158158
parser->tank[i].gasmix = DC_GASMIX_UNKNOWN;
159-
parser->tank[i].usage = DC_USAGE_NONE;
159+
parser->tank[i].usage = DC_TANK_USAGE_NONE;
160160
}
161161

162162
*out = (dc_parser_t *) parser;
@@ -440,7 +440,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
440440
unsigned int DC_ATTR_UNUSED battery = array_uint16_le (data + offset + 4);
441441
unsigned int pressure = array_uint16_le (data + offset + 6);
442442
unsigned int transmitter = array_uint16_le (data + offset + 8);
443-
dc_usage_t usage = DC_USAGE_NONE;
443+
dc_tank_usage_t usage = DC_TANK_USAGE_NONE;
444444

445445
if (have_gasmix && gasmix_id_previous != gas_id) {
446446
unsigned int idx = 0;
@@ -561,7 +561,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
561561
}
562562
unsigned int pressure = array_uint16_le (data + offset + 8);
563563
unsigned int serial = array_uint16_le (data + offset + 10);
564-
dc_usage_t usage = DC_USAGE_OXYGEN;
564+
dc_tank_usage_t usage = DC_TANK_USAGE_NONE;
565565

566566
if (tank_id_previous != serial ||
567567
tank_usage_previous != usage) {
@@ -642,7 +642,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
642642
unsigned int id = data[offset + 2] | TRANSMITTER_ID;
643643
unsigned int DC_ATTR_UNUSED battery = array_uint16_le (data + offset + 4);
644644
unsigned int pressure = array_uint16_le (data + offset + 6) / 10;
645-
dc_usage_t usage = DC_USAGE_NONE;
645+
dc_tank_usage_t usage = DC_TANK_USAGE_NONE;
646646

647647
if (tank_id_previous != id ||
648648
tank_usage_previous != usage) {

src/parser.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned
198198
rc = deepsix_excursion_parser_create (&parser, context, data, size);
199199
break;
200200
case DC_FAMILY_SEAC_SCREEN:
201-
rc = seac_screen_parser_create (&parser, context, data, size);
201+
rc = seac_screen_parser_create (&parser, context, data, size, model);
202202
break;
203203
case DC_FAMILY_DEEPBLU_COSMIQ:
204204
rc = deepblu_cosmiq_parser_create (&parser, context, data, size);

src/seac_screen.c

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,16 @@
4949

5050
#define CMD_HWINFO 0x1833
5151
#define CMD_SWINFO 0x1834
52-
#define CMD_RANGE 0x1840
53-
#define CMD_ADDRESS 0x1841
54-
#define CMD_READ 0x1842
52+
53+
// Screen
54+
#define CMD_SCREEN_RANGE 0x1840
55+
#define CMD_SCREEN_ADDRESS 0x1841
56+
#define CMD_SCREEN_READ 0x1842
57+
58+
// Tablet
59+
#define CMD_TABLET_RANGE 0x1850
60+
#define CMD_TABLET_ADDRESS 0x1851
61+
#define CMD_TABLET_READ 0x1852
5562

5663
#define SZ_HWINFO 256
5764
#define SZ_SWINFO 256
@@ -65,15 +72,29 @@
6572
#define FP_OFFSET 0x0A
6673
#define FP_SIZE 7
6774

68-
#define RB_PROFILE_BEGIN 0x010000
69-
#define RB_PROFILE_END 0x200000
70-
#define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN)
71-
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END)
72-
#define RB_PROFILE_INCR(a,d) ringbuffer_increment (a, d, RB_PROFILE_BEGIN, RB_PROFILE_END)
75+
#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, l->rb_profile_begin, l->rb_profile_end)
76+
#define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end)
77+
78+
#define ACTION 0x01
79+
#define SCREEN 0x02
80+
#define TABLET 0x10
81+
82+
typedef struct seac_screen_commands_t {
83+
unsigned short range;
84+
unsigned short address;
85+
unsigned short read;
86+
} seac_screen_commands_t;
87+
88+
typedef struct seac_screen_layout_t {
89+
unsigned int rb_profile_begin;
90+
unsigned int rb_profile_end;
91+
} seac_screen_layout_t;
7392

7493
typedef struct seac_screen_device_t {
7594
dc_device_t base;
7695
dc_iostream_t *iostream;
96+
const seac_screen_commands_t *cmds;
97+
const seac_screen_layout_t *layout;
7798
unsigned char info[SZ_HWINFO + SZ_SWINFO];
7899
unsigned char fingerprint[FP_SIZE];
79100
} seac_screen_device_t;
@@ -100,6 +121,28 @@ static const dc_device_vtable_t seac_screen_device_vtable = {
100121
NULL, /* close */
101122
};
102123

124+
static const seac_screen_commands_t cmds_screen = {
125+
CMD_SCREEN_RANGE,
126+
CMD_SCREEN_ADDRESS,
127+
CMD_SCREEN_READ,
128+
};
129+
130+
static const seac_screen_commands_t cmds_tablet = {
131+
CMD_TABLET_RANGE,
132+
CMD_TABLET_ADDRESS,
133+
CMD_TABLET_READ,
134+
};
135+
136+
static const seac_screen_layout_t layout_screen = {
137+
0x010000, /* rb_profile_begin */
138+
0x200000, /* rb_profile_end */
139+
};
140+
141+
static const seac_screen_layout_t layout_tablet = {
142+
0x0A0000, /* rb_profile_begin */
143+
0x200000, /* rb_profile_end */
144+
};
145+
103146
static dc_status_t
104147
seac_screen_send (seac_screen_device_t *device, unsigned short cmd, const unsigned char data[], size_t size)
105148
{
@@ -284,6 +327,8 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t
284327

285328
// Set the default values.
286329
device->iostream = iostream;
330+
device->cmds = NULL;
331+
device->layout = NULL;
287332
memset (device->info, 0, sizeof (device->info));
288333
memset (device->fingerprint, 0, sizeof (device->fingerprint));
289334

@@ -327,6 +372,15 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t
327372

328373
HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Software", device->info + SZ_HWINFO, SZ_SWINFO);
329374

375+
unsigned int model = array_uint32_le (device->info + 4);
376+
if (model == TABLET) {
377+
device->cmds = &cmds_tablet;
378+
device->layout = &layout_tablet;
379+
} else {
380+
device->cmds = &cmds_screen;
381+
device->layout = &layout_screen;
382+
}
383+
330384
*out = (dc_device_t *) device;
331385

332386
return DC_STATUS_SUCCESS;
@@ -379,7 +433,8 @@ seac_screen_device_read (dc_device_t *abstract, unsigned int address, unsigned c
379433
(len ) & 0xFF,
380434
};
381435
unsigned char packet[SZ_READ] = {0};
382-
status = seac_screen_transfer (device, CMD_READ, params, sizeof(params), packet, sizeof(packet));
436+
const unsigned int packetsize = device->cmds->read == CMD_TABLET_READ ? len : sizeof(packet);
437+
status = seac_screen_transfer (device, device->cmds->read, params, sizeof(params), packet, packetsize);
383438
if (status != DC_STATUS_SUCCESS) {
384439
ERROR (abstract->context, "Failed to send the read command.");
385440
return status;
@@ -400,11 +455,16 @@ static dc_status_t
400455
seac_screen_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
401456
{
402457
seac_screen_device_t *device = (seac_screen_device_t *) abstract;
458+
const seac_screen_layout_t *layout = device->layout;
403459

404460
// Emit a device info event.
405461
dc_event_devinfo_t devinfo;
406462
devinfo.model = array_uint32_le (device->info + 4);
407-
devinfo.firmware = array_uint32_le (device->info + 0x11C);
463+
if (devinfo.model == TABLET) {
464+
devinfo.firmware = array_uint32_le (device->info + 0x114);
465+
} else {
466+
devinfo.firmware = array_uint32_le (device->info + 0x11C);
467+
}
408468
devinfo.serial = array_uint32_le (device->info + 0x10);
409469
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
410470

@@ -415,12 +475,12 @@ seac_screen_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
415475
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
416476

417477
// Allocate the required amount of memory.
418-
if (!dc_buffer_resize (buffer, RB_PROFILE_SIZE)) {
478+
if (!dc_buffer_resize (buffer, layout->rb_profile_end - layout->rb_profile_begin)) {
419479
ERROR (abstract->context, "Insufficient buffer space available.");
420480
return DC_STATUS_NOMEMORY;
421481
}
422482

423-
return device_dump_read (abstract, RB_PROFILE_BEGIN, dc_buffer_get_data (buffer),
483+
return device_dump_read (abstract, layout->rb_profile_begin, dc_buffer_get_data (buffer),
424484
dc_buffer_get_size (buffer), SZ_READ);
425485
}
426486

@@ -429,16 +489,21 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
429489
{
430490
dc_status_t status = DC_STATUS_SUCCESS;
431491
seac_screen_device_t *device = (seac_screen_device_t *) abstract;
492+
const seac_screen_layout_t *layout = device->layout;
432493

433494
// Enable progress notifications.
434495
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
435-
progress.maximum = RB_PROFILE_SIZE;
496+
progress.maximum = layout->rb_profile_end - layout->rb_profile_begin;
436497
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
437498

438499
// Emit a device info event.
439500
dc_event_devinfo_t devinfo;
440501
devinfo.model = array_uint32_le (device->info + 4);
441-
devinfo.firmware = array_uint32_le (device->info + 0x11C);
502+
if (devinfo.model == TABLET) {
503+
devinfo.firmware = array_uint32_le (device->info + 0x114);
504+
} else {
505+
devinfo.firmware = array_uint32_le (device->info + 0x11C);
506+
}
442507
devinfo.serial = array_uint32_le (device->info + 0x010);
443508
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
444509

@@ -450,7 +515,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
450515

451516
// Read the range of the available dive numbers.
452517
unsigned char range[SZ_RANGE] = {0};
453-
status = seac_screen_transfer (device, CMD_RANGE, NULL, 0, range, sizeof(range));
518+
status = seac_screen_transfer (device, device->cmds->range, NULL, 0, range, sizeof(range));
454519
if (status != DC_STATUS_SUCCESS) {
455520
ERROR (abstract->context, "Failed to send the range command.");
456521
goto error_exit;
@@ -486,7 +551,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
486551
unsigned int count = 0;
487552
unsigned int skip = 0;
488553
unsigned int rb_profile_size = 0;
489-
unsigned int remaining = RB_PROFILE_SIZE;
554+
unsigned int remaining = layout->rb_profile_end - layout->rb_profile_begin;
490555
for (unsigned int i = 0; i < ndives; ++i) {
491556
unsigned int number = last - i;
492557

@@ -498,15 +563,15 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
498563
(number ) & 0xFF,
499564
};
500565
unsigned char rsp_address[SZ_ADDRESS] = {0};
501-
status = seac_screen_transfer (device, CMD_ADDRESS, cmd_address, sizeof(cmd_address), rsp_address, sizeof(rsp_address));
566+
status = seac_screen_transfer (device, device->cmds->address, cmd_address, sizeof(cmd_address), rsp_address, sizeof(rsp_address));
502567
if (status != DC_STATUS_SUCCESS) {
503568
ERROR (abstract->context, "Failed to read the dive address.");
504569
goto error_free_logbook;
505570
}
506571

507572
// Get the dive address.
508573
logbook[i].address = array_uint32_be (rsp_address);
509-
if (logbook[i].address < RB_PROFILE_BEGIN || logbook[i].address >= RB_PROFILE_END) {
574+
if (logbook[i].address < layout->rb_profile_begin || logbook[i].address >= layout->rb_profile_end) {
510575
ERROR (abstract->context, "Invalid ringbuffer pointer (0x%08x).", logbook[i].address);
511576
status = DC_STATUS_DATAFORMAT;
512577
goto error_free_logbook;
@@ -543,11 +608,11 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
543608

544609
// Get the end-of-profile pointer.
545610
if (eop == 0) {
546-
eop = previous = RB_PROFILE_INCR (logbook[i].address, nbytes);
611+
eop = previous = RB_PROFILE_INCR (logbook[i].address, nbytes, layout);
547612
}
548613

549614
// Calculate the length.
550-
unsigned int length = RB_PROFILE_DISTANCE (logbook[i].address, previous);
615+
unsigned int length = RB_PROFILE_DISTANCE (logbook[i].address, previous, layout);
551616

552617
// Check for the end of the ringbuffer.
553618
if (length > remaining) {
@@ -567,7 +632,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
567632

568633
// Update and emit a progress event.
569634
progress.maximum -= (ndives - count - skip) * (SZ_ADDRESS + SZ_HEADER) +
570-
(RB_PROFILE_SIZE - rb_profile_size);
635+
((layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size);
571636
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
572637

573638
// Exit if no dives to download.
@@ -584,7 +649,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
584649

585650
// Create the ringbuffer stream.
586651
dc_rbstream_t *rbstream = NULL;
587-
status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, RB_PROFILE_BEGIN, RB_PROFILE_END, eop, DC_RBSTREAM_BACKWARD);
652+
status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
588653
if (status != DC_STATUS_SUCCESS) {
589654
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
590655
goto error_free_profile;
@@ -594,7 +659,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
594659
unsigned int offset = rb_profile_size;
595660
for (unsigned int i = 0; i < count; ++i) {
596661
// Calculate the length.
597-
unsigned int length = RB_PROFILE_DISTANCE (logbook[i].address, previous);
662+
unsigned int length = RB_PROFILE_DISTANCE (logbook[i].address, previous, layout);
598663

599664
// Move to the start of the current dive.
600665
offset -= length;

src/seac_screen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ dc_status_t
3535
seac_screen_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
3636

3737
dc_status_t
38-
seac_screen_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
38+
seac_screen_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
3939

4040
#ifdef __cplusplus
4141
}

src/seac_screen_parser.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,15 @@
3636

3737
#define INVALID 0xFFFFFFFF
3838

39+
#define ACTION 0x01
40+
#define SCREEN 0x02
41+
#define TABLET 0x10
42+
3943
typedef struct seac_screen_parser_t seac_screen_parser_t;
4044

4145
struct seac_screen_parser_t {
4246
dc_parser_t base;
47+
unsigned int model;
4348
// Cached fields.
4449
unsigned int cached;
4550
unsigned int ngasmixes;
@@ -65,7 +70,7 @@ static const dc_parser_vtable_t seac_screen_parser_vtable = {
6570
};
6671

6772
dc_status_t
68-
seac_screen_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
73+
seac_screen_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
6974
{
7075
seac_screen_parser_t *parser = NULL;
7176

@@ -80,6 +85,7 @@ seac_screen_parser_create (dc_parser_t **out, dc_context_t *context, const unsig
8085
}
8186

8287
// Set the default values.
88+
parser->model = model;
8389
parser->cached = 0;
8490
parser->ngasmixes = 0;
8591
for (unsigned int i = 0; i < NGASMIXES; ++i) {
@@ -298,6 +304,7 @@ seac_screen_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
298304
unsigned int decodepth = array_uint16_le (data + offset + 0x0E);
299305
unsigned int decotime = array_uint16_le (data + offset + 0x10);
300306
unsigned int ndl_tts = array_uint16_le (data + offset + 0x12);
307+
unsigned int pressure = array_uint16_le (data + offset + 0x14);
301308
unsigned int cns = array_uint16_le (data + offset + 0x16);
302309
unsigned int gf_hi = data[offset + 0x3B];
303310
unsigned int gf_lo = data[offset + 0x3C];
@@ -366,6 +373,13 @@ seac_screen_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
366373
sample.cns = cns / 100.0;
367374
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
368375

376+
// Tank pressure
377+
if (pressure && parser->model == TABLET) {
378+
sample.pressure.tank = 0;
379+
sample.pressure.value = pressure;
380+
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
381+
}
382+
369383
// Deco model
370384
if (gf_low == 0 && gf_high == 0) {
371385
gf_low = gf_lo;

src/shearwater_predator_parser.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
598598
tank[id].endpressure = pressure;
599599
}
600600
tank[id].endpressure = pressure;
601-
tank[id].battery = 0;
601+
tank[id].battery |= battery;
602602
}
603603
}
604604
}

0 commit comments

Comments
 (0)