In ViatomLoader.cpp in the ViatomFile:
arseHeader() function:
Code:
const unsigned char* header = (const unsigned char*) data.constData();
int sig = header[0] | (header[1] << 8);
int year = header[2] | (header[3] << 8);
int month = header[4];
int day = header[5];
int hour = header[6];
int min = header[7];
int sec = header[8];
The first byte of the header, called
sig in this case, is later referred to in several places as if it identifies a "CheckMe O2 Max", such as here in ReadData():
Code:
if (m_sig == 5) {
// Confirm that CheckMe O2 Max is a true 2s sample rate.
CHECK_VALUE(all_are_duplicated, false);
} else {
// Confirm that older models are actually a 4s sample rate.
CHECK_VALUE(m_sig, 3);
CHECK_VALUE(all_are_duplicated, true);
}
However, the first byte in the header file corresponds to the File Version in the O2 Insight database, regardless of model type as shown here:
I have verified that the binary file formats are identical for the OxyLink, O2 Ring, and Wear O2 models from Viatom with variations on the following code:
Code:
[TestMethod]
public void ReadViatomBinaryFile()
{
const int HEADER_SIZE = 40;
const int RECORD_SIZE = 5;
string path = @"[REDACTED, CHANGES ACCORDING TO WHICH FILE I WANT TO TEST]";
Assert.IsTrue( File.Exists( path ) );
using var file = File.OpenRead( path );
using var reader = new BinaryReader( file );
int fileVersion = reader.ReadInt16();
Assert.IsTrue( fileVersion is 3 or 5 ); // Never actually encountered FileVersion=5, but apparently someone else has and it's binary compatible
int year = reader.ReadInt16();
Assert.AreEqual( 2023, year );
int month = reader.ReadByte();
Assert.IsTrue( month >= 1 && month <= 12 );
int day = reader.ReadByte();
Assert.IsTrue( day is >= 1 and <= 31 );
int hour = reader.ReadByte();
Assert.IsTrue( hour is >= 0 and <= 24 );
int minute = reader.ReadByte();
Assert.IsTrue( minute is >= 0 and <= 60 );
int second = reader.ReadByte();
Assert.IsTrue( second is >= 0 and <= 60 );
var expectedTimestamp = DateTime.Parse( "2023-10-04 03:17:47.000" );
var headerTimestamp = new DateTime( year, month, day, hour, minute, second );
Assert.AreEqual( expectedTimestamp, headerTimestamp );
// Read timestamp (NOTE: The filename also appears to be a timestamp. Do they always match?)
var filenameTimestamp = DateTime.ParseExact( Path.GetFileName( path ), "yyyyMMddHHmmsss", CultureInfo.InvariantCulture );
Assert.AreEqual( expectedTimestamp, filenameTimestamp );
// Read and validate file size
int fileSize = reader.ReadInt32();
Assert.AreEqual( file.Length, fileSize );
// Read duration of recording
var duration = TimeSpan.FromSeconds( reader.ReadInt16() );
Assert.AreEqual( TimeSpan.FromSeconds( 5316 ), duration );
// Skip the rest of the header, as it doesn't provide any useful information for us.
file.Position = HEADER_SIZE;
// The rest of the file should be an exact multiple of RECORD_SIZE
Assert.AreEqual( 0, (fileSize - HEADER_SIZE) % RECORD_SIZE );
int recordCount = (fileSize - HEADER_SIZE) / RECORD_SIZE;
double frequency = 1.0 / (duration.TotalSeconds / recordCount);
for( int i = 0; i < recordCount; i++ )
{
var spO2 = reader.ReadByte();
var pulse = reader.ReadByte();
var isInvalid = reader.ReadByte();
var motion = reader.ReadByte();
var vibration = reader.ReadByte();
Debug.WriteLine( $"OX: {spO2}, PULSE: {pulse}, MOT: {motion}, INVALID: {isInvalid}, VIB: {vibration}" );
}
}