Download operation
In some deployment scenarios, it can be preferable to periodically download the binary contents of instrument memory. Partial instrument memory can be retrieved, and this is the suggested way of reading memory. And, the instrument can be deployed via commands sent over the HEM without the use of Ruskin.
Please refer to the command references for the MLM and the instrument to understand the sleep behaviour of both. You'll need to wake the HEM before it will respond to commands, and then do the same for the instrument after establishing a transparent link with the SSM. Summarized, the behaviour is such that when you haven't interacted with either the HEM or the instrument in more than 10s, you must send a newline character (carriage return or line feed) then wait ~50ms before the unit will respond to further commands. For brevity, I'll elide the wake sequence from the following examples.
Once connected to the HEM, send the A command to confirm you're talking to it:
>> A<cr>
<< <tab>RBR HEM-1000 1.300 023077<cr><lf>
(HEM commands can be terminated with <cr>, <lf>, or both. HEM command responses are prefixed with a horizontal <tab> character and are line-terminated with <cr><lf>. I'll omit all termination from subsequent examples.)
If you instead receive
<< RBR RBRvirtuoso3 1.092 052877
then the HEM is already in transparent mode.
To open a transparent link between the HEM and instrument via the SSM, you can use the xtp command:
>> xtp 023458
<< tp channel requested (with ssm 023458)...GRANTED
<< ***transparent mode***
Once connected, you can use the id command to confirm that you're talking directly to the instrument:
>> id<cr>
<< id model = RBRvirtuoso3, version = 1.092, serial = 52877, fwtype = 104<cr><lf>
<< Ready:
(Like HEM commands, instrument commands can be terminated with <cr>, <lf>, or both. Instrument command responses are line-terminated with <cr><lf> and followed by a “Ready: ” prompt. You can use either as a delimiter for responses. Again, I'll omit termination from examples except where it varies significantly.)
To setup the instrument and start the deployment:
% Stop any previous deployment.
>> disable
<< disable status = disabled
% Synchronize the instrument clock.
>> clock datetime = 20180910192557
<< clock datetime = 20180910192557
% Schedule the instrument to start logging at the beginning of time/stop logging at the end of time (i.e., log immediately and infinitely).
>> deployment starttime = 20000101000000, endtime = 20991231235959
<< deployment starttime = 20000101000000, endtime = 20991231235959
% Configure the sampling behaviour: 1-minute average of 4Hz data (240 continuous samples), recorded every 5 minutes (300,000 milliseconds).
>> sampling mode = average, period = 250, burstlength = 240, burstinterval = 300000
<< sampling mode = average, period = 250, burstlength = 240, burstinterval = 300000
% Record to memory in “EasyParse” format: an array of fixed-width samples.
>> memformat newtype = calbin00
<< memformat newtype = calbin00
% Begin the deployment.
>> enable erasememory = true
<< enable status = logging, warning = W0401
% The warning is because an unbounded deployment will fill instrument memory.
% Determine how many channels are enabled; this will determine the byte size of each sample.
>> channels on
<< channels on = 3
% Find out what those channels are.
>> channel allindices status, userunits, label
<< channel 1 status = on, userunits = dbar, label = pressure_00 || channel 2 status = on, userunits = dbar, label = seapressure_00 || channel 3 status = on, userunits = m, label = depth_00
In this example, each sample will occupy (1 × 64-bit timestamp + 3 × 32-bit channels) = (8 bytes + 3 × 4 bytes) = 20 bytes of instrument memory.
Then, periodically, you can download the contents of instrument memory:
% See how much memory is used.
>> meminfo dataset = 1, used
<< meminfo dataset = 1, used = 15652
% Download new data. For ease of parsing, you'll want to download chunks which multiples of and aligned with the byte size of a sample. In this case, we'll download 100 samples, starting at the 200th sample.
>> readdata dataset = 1, size = 2000, offset = 4000
<< readdata dataset = 1, size = 2000, offset = 4000<cr><lf><bytes[4000..5999]-of-data><crc><cr><lf>
<< Ready:
See https://docs.rbr-global.com/L3commandreference/commands/memory-and-data-retrieval/readdata for details. The data between the <cr><lf> pairs is binary and will contain null characters, so avoid the use of string functions in reading it. A 2-byte CRC trails the requested chunk. Please let us know which language you'll be writing your controller in so we can provide you with a corresponding implementation of the CRC function. It can be tricky to get right and we've probably already done it for your target.
To close transparent mode and put the SSM to sleep, you'll first need to send the escape sequence. This consists of 750ms of inactivity, followed by the character 0x01 (Ctrl+A) three times, followed by another 750ms of inactivity.
>> ^A^A^A
<< ***command mode***
Once in command mode, you can use the zzz command to put the SSM to sleep; x k command to cause the HEM to close the channel; and then the zzz command to put the HEM to sleep:
>> .zzz
% The SSM will immediately sleep without producing any response.
>> x k
<< channel closed
>> zzz
% The HEM will similarly sleep without response.
The binary data downloaded can be interpreted as an array of samples where each sample consists of a 64-bit number of milliseconds since 1970-01-01T00:00:00.000Z followed by a 32-bit IEEE 754 floating point number for each channel. Values are stored little-endian. So for example, to iterate through a downloaded chunk and print all the samples (without formatting timestamps):
#define CHANNEL_MAX 32
typedef struct Sample
{
uint64_t timestamp;
float values[CHANNEL_MAX];
} Sample;
void print_samples(void *chunk, ssize_t chunk_size, ssize_t channel_count)
{
uint8_t *cchunk = (uint8_t *) chunk;
ssize_t sample_size = sizeof(uint64_t) + channel_count * sizeof(float);
Sample *sample;
for (ssize_t offset = 0;
offset <= chunk_size - sample_size;
offset += sample_size)
{
sample = (Sample *) (cchunk + offset);
printf("%" PRIi64, sample->timestamp);
for (ssize_t channel = 0; channel < channel_count; channel++)
{
printf(", %f", sample->values[channel]);
}
printf("\n");
}
}