Loader was checking that maskoff time was not greater than current time. This
produced problems when CPAP machine was set to DST but computer was set to standard
time. This also could cause problems trying to import files created in a different
timezone.
Added a separate check for maskon and maskoff times were in legal range (0-24*60).
Updated release notes.
Prevoiusly, disabling an oximeter session could cause bookmarks to be
disabled and/or OSCAR to crash. OSCAR was looking up the session for
the oximeter session and not noticing it got a Journal session instead.
We do this by forcing a UTF-8 byte order marker in the profile.xml file.
We also add processing instructions that specify UTF-8, although it seems the BOM is itself sufficient.
1) If data compression option is set, loader will now try the str.edf.gz file first, with fallback to str.edf
2) Mixed Windows and Unix separators are now allowed in --datadir, which was previously causing data loss when rebuilding CPAP data.
1) If data compression option is set, loader will now try the str.edf.gz file first, with fallback to str.edf
2) Mixed Windows and Unix separators are now allowed in --datadir, which was previously causing data loss when rebuilding CPAP data.
- Changed Profile::GetMachine() to find machine with latest lastImportDate when there were multiple machines in a profile.
- Previously, OSCAR would shown the "first" machine in its list, without clarity about how a machine was designated "first".
- If trying to delete a profile folder with no contents, now displays an error message and doesn't delete it.
- Folders with no contents are no longer listed on the Profiles page.
- Release Notes updated with the fixes for beta-2.
- Previously, would stop and return 0 if any day in range was suumary only
- Now, just ignores summary-only days if there are days with data
- Re-indentation makes change look bigger than it is
- Values of "On" and "Plus" will be shown for this field.
- Field name will remain Patient Access until a new profile is created or language is changed.
- make Day::validPressure() available
- Welcome page to report n/a if pressure not valid (but it should always be valid)
- Did NOT add validPressure() call to all pressure reports.
- Oximetry loader from file now remembers last directory data was imported from.
- ResMed loader loads from last day or oldest purge date if a day was purged since last import.
purgeDate added to MachineInfo to implement this. Purge date set when a day is purged and cleared after an import.
- Fix possible problem with rebuilding CPAP data
- Change re-import to look just at last day (full re-import will be re-added later)
- Improve detection of when a day needs to be rebuilt on re-import
- Improve some diagnostic messages
o Now compares all days, not just starting from last day imported
o Compares number of non-identical MaskOn/Off events with session count
o Hid most qDebug messages behind #define STR_EDF
o Added qWarning to open() and close() calls for improved diagnostics
o Fixed some copy() calls that were not working
file.open() checked everywhere except in loaders.
qWarning() message written to debug log, with error number and text.
We may want to exit OSCAR with a message in many situations, but that is not implemented yet.
Set number of debug logs to be kept for Release version to 4.
Daily page: total hours was elapsed time of all machines, including large blocks that are not CPAP. Now just MT_CPAP time.
Welcome page: Same problem with total hours reporting, and AHI was calculated as events/total hours instead of events/CPAP hours.
Statistics page: Same problems as on Welcome page -- total hours and index calculations. Changed to using total CPAP hours.
Evidently gcc doesn't recognize inline forward declaration, but clang does.
I wonder who is right?
This was previously addressed by adding an #include. Instead, this patch
adds a standalone forward declaration of the QXmlStreamReader/Writer classes.
This has been tested and verified to compile with gcc and clang.
This is transparent to the user and is recorded into a log directory within
the OSCAR_Data directory.
Also add log rotation so that these logs don't grow forever.
The only code change was to move XmlReplayEvent::s_factories into
a local static variable accessed by XmlReplayEvent::factories() to
ensure that it will be initialized before it is used.
Otherwise there is no guarantee in C++11 that global variables
in different source files (translation units) will be initialized
in any particular order.
This is significant now because it will allow accurate recording of
multiple simultaneous connections.
This is important for the future because it establishes the
necessary infrastructure for recording downloaded sessions into their
own files so that they can be saved as backups.
Now a replayed read() will return the response that follows the
matching write().
When calls are made in the same order as they were during recording,
this will have no effect, and the original ordering will be replayed.
However, minor changes to the code should still result in sensible
replay until a new recording can be made.
Calling openConnection will return an open connection or nullptr.
Deleting the connection will close it.
SerialPort now uses this under the hood, while still presenting
the QSerialPort-compatible interface.
Checks for updates to OSCAR at startup and profile close.
Also allows user to check with Help/Check for updates.
Updates controlled by versions.xml in www.sleepfiles.com/oscar/versions
This initial commit is designed to change as little existing code as possible.
Once regression tests are in place that can play back previously recorded
data, we can move on to more significant changes.
The VS2 channel is unique in that it only appears (as a flag)
when there are nonzero snores during a 2-minute period. However, the
VS index isn't the number of events (nonzero intervals) per hour,
but rather the number of snores per hour.
This only affected PRS1, and it seems like the other places where
the broken Session::hours() result was used were:
- GT_SESSIONS, which seems to be unused
- settings_wavg, where it had no effect
The other uses of Settings::hours() were where there was only
a single slice, in which case it returned the right result:
- gSessionTimesChar::paint (the one still in use)
- Icon loader
- Resmed loader
Import was working, but the consistency checks made a few assumptions
that turned out not to be universally applicable, so they were
making a lot of unnecessary noise.
In particular F3V3 won't always create IPAPmin/max settings when in
CPAP mode or with a single IPAP setting.
Also consider ventilators to have a flex mode of "Rise Time" when
they have a rise time configured.
DreamStation ramp time and mask resistance "off" settings are now also imported.
Ventilator alarms are not yet parsed reliably enough to import at this time.
Also update Detect to retain its original behavior of letting the user
select the P-Series folder instead of the root.
Also fix what looked like a hang when backing up PRS1 files. The
progress bar still doesn't update during backup, but at least it
now says that it's backing up and the UI remains responsive.
Thanks to mjphyi for tracking this down!
gcc didn't provide very useful error messages, saying that
error: invalid conversion from ‘long int’ to ‘QDebug::Stream*’
was in qglobal.h.
But it really had to do with a few scattered #defines in OSCAR changing
nullptr to NULL (an int). Since OSCAR now requires C++11, and nullptr
is a keyword in C++11, these #defines can go.
Resolves issue #5.
Ideally graphs would be able to invert their Y axis without this hack, but
it works for now. It would also be good to support non-numeric labels
in the graph legend.
This changes the parsing to distinguish between the "flex pressure" reported
by single-pressure modes (which remains effectively EPAP) and the average
pressure reported by bi-level modes (which returns to its former average
pressure channel).
It looks like SaveSummaryCache() would occasionally get called elsewhere
under certain circumstances, which would cause sessions to occasionally
save, but unpredictably. Now the summary cache gets saved consistently.
This removes git dependencies from everything except for version.cpp,
and removes the associated interfaces in version.h.
Since the full version string contains the branch and revision
number where applicable, the build information no longer needs
to report branch and revision separately. It also now queries
version.cpp for a more consistent and reliable build time.
Debug output of build information is also now more consistent with
less redundant code.
The full version now includes the build/git information embedded within
it as build metadata according to the Semantic Versioning 2.0.0 spec,
for example: "1.1.0-beta-1+branch-name-a1b2c3d".
Now the full version string, with all detail is always displayed
EXCEPT for release versions, in which case just the simple version
number ("1.1.0") is displayed in the primary UI.
- Main window title: simple version for release versions, full version
string otherwise
- Notifications: same as main window title
- System tray: same as main window title
- About window title: same as main window title
- About window release notes: always include full version string
- Reports: always include full version string
- Under the logo (about dialog, profile selector, new profile
window): removed, as it is largely redundant and can
interfere with the window geometry.
- Database upgrade alert: same as main window title
- Database newer alert: same as main window title
The full version string is also included within the preference and
profile .xml files, but because build metadata is ignored in version
comparisons, differences in builds will not cause any spurious
alerts. However, changes in prerelease versions will continue to
be significant, as they should be.
Previously it was reporting spurious information when the humidifier was
disconnected. Now it only reports settings details when the humidifier is
connected (the only time they're valid.)
It also now reports the humidification mode (fixed, adaptive, or heated
tube), and the heated tube temperature when appropriate.
No real change to functionality, other than confirming correct behavior,
documenting observed data and adding flags for anything new.
The ParseHumidifierSettingF0V4 function has now been renamed to
ParseHumidifierSetting60Series for accuracy.
Accordingly update ParseHumidifierSetting50Series to add a parameter
controlling whether parsed settings should be imported or not,
consistent with all other PRS1 humidifier parsers.
The ParseHumidifierSettingV2 function has now been renamed to
ParseHumidifierSetting50Series for accuracy, and the code and
parameters which had been used when 60-Series machines (incorrectly)
relied on it has been removed.
The last statistics events in each slice are now correctly imported.
Previously, in the surprising edge case where two statistic periods are
reported with the same end-of-slice timestamp, they were both being duplicated
when marking the end of the slice.
Also, there were scattered instances where the final statistics in a slice
weren't being imported at all or were being imported incorrectly. These are
now fixed as well.
No change in import behavior yet, but this will be needed to deal with a weird edge
case in which two statistic periods are reported with the same end-of-slice timestamp,
the first one intended to cover the preceding 2 minutes, the second one presumably
intended to cover the fractional second after the previous interval, though all
values are 0, so it's hard to be sure.
Because opening a profile already had a progress dialog open, the import
process during a forced rebuild wasn't appearing, so it would look like
OSCAR was hanging for as long as the import took.
Temporarily hiding the profile progress dialog resolves the issue.
This was bumped once already after the previous release version, but
bumping it again now will make sure that all beta testers are working
from data based on the current state of the PRS1 loader.
Settings are written as soon as a day is viewed, so anybody who viewed
their PRS1 data prior to the previous commit would have settings with the
channels expressly disabled. Changing the channel ID forces them to be
treated as new, and thus default to on.
Also add support for parsing and proceeding past a previously
unseen F5V0 event, though for now it's just getting swallowed
since its meaning isn't entirely clear.
This adds BND flagging to machines without waveform data, such as F3V3 (1160P)
and bricks (250P, 200X), as well as sessions for which waveform data was
unavailable. It also catches BNDs at the end of a session, which were
previously missed.
By duplicating the last reported event at its originally reported
event (clamped to the slice end time for F3V3), charts will now
correctly show the value during that last interval.
Also fix some slice sanity checks so they don't yell when F3V3
skips an event chunk.
This now correctly shows gaps in therapy and statistics when the
mask is off. It also corrects the initial statistics for some sessions
to 1 second later, when the initial mask-on slice begins 1 second
after the session starts.
Weird zero-length PB and LL events are now dropped on import, since
they wouldn't get drawn anyway and seem to be peculiar artifacts.
If there are no mask-on slices of nonzero duration, then there's not any
meaningful event or waveform data for the session. There is occasionally some
fragmentary data, but it's always less than 1 second.
When such fragmentary waveform data is present, it only contains 1-3 nonzero
samples, corresponding to 0.2s - 0.6s of data, which suggests that the
mask-on slice was really that long rather than precisely 0. As a result,
it appears that the timestamps of the mask-on/mask-off slices are just the
current value of the machine's internal clock, which only has 1-second
resolution.
But rather than embark on herculean efforts to derive a sub-second slice
duration from (only occasionally present) event or waveform data, we just
treat the session as having no detailed data.
Because summaries used to be parsed incorrectly, there was a bunch of ugly
logic that was designed to infer the session start & end times from other data.
Now that the summary parsers work, that can all go away. The only change to
imported data is that sessions ending with the mask off are now longer, to
reflect that extra time before the machine was turned off.
This now correctly shows gaps in therapy and statistics when the
mask is off. It currently only works for F3V3, since it has a
separate event chunk per slice. Other machines, which have only
a single large event chunk, will need to track the slices as
they import events.
This also highlights the issue with the last statistics in a
slice: only one data point is imported indicating the start of
a measured value, and so it appears that the data terminates then
instead of at the end of the slice (seconds to minutes later).
This fixes a regression introduced by fda9fcd1, which fixed import for
all the other machines but broke F3V3.
Also move the generation of HY/CA/OA events out of the parser and into
the importer.
This will let us create "duplicate" statistical events at the end of
a session (and eventually slice) to reflect the end time of each
measurement channel.
PRS1 statistics are reported at the end of a 2-minute interval,
but OSCAR assumes the timestamp for the statistics is their
starting timestamp.
This resolves the issue where statistics wouldn't appear for the
first two minutes of a session, and then would consistently be
2 minutes delayed.
There are still some edge cases to deal with, but the general
case is much improved.
Also clean up unused PRS1 channels and fix a regression from
9a25647c that broke unintentional leak calculation for CPAP/APAP.
Also add PRS1PressureAverageEvent to F0V4 list of supported events.
Right now this results in slightly confusing graphs, since sometimes
the IPAP/EPAP data for a machine is primarily reported by its settings
events, and for other machines by its statistics events. Also, the
"average" pressure on F0 looks like it might be effectivley EPAP in
single-pressure mode rather than the true average in bi-level mode.
Once we decide on the best presentation, we can either update the importer
or the display to show the most helpful channels for a given session.
Occasionally waveforms in a DreamStation session can be split into
multiple files. This behavior resulted in a report of missing waveform
data, and upon investigation was found 15 times out of 10,000 sample
sessions.
It looks like this happens when the machine begins writing the waveform
file before realizing that it will hit its 500-file-per-directory limit
for the remaining session files, at which point it appears to write
the rest of the waveform data along with the summary and event files
in the next directory.
The previous commit added better testing support and warning messages
for when this is encountered. This commit fixes the issue, and so
the warning is no longer necessary.
Also warn when waveform files are being skipped on import due to this
kind of splitting.
The chunks YAML now emits all unique chunks found in files with the
same session ID.
Note that a single file can contain multiple chunks covering multiple
sessions. These will all be saved in the YAML file corresponding to the
original file's name, rather than the session ID encoded in any chunk.
This slight discrepancy is intentional, since the chunk YAML is meant
to test the parsers, to verify that they correctly decode a specific
input file. When importing data into a session, we use the actual
session ID specified by each chunk. Thus the session YAML files will
be derived from the proper chunks, regardless of their original
containing file. (Well, except for waveforms, but they don't appear
to have more than one session ID per file.)
F3V3 events are formatted as waveforms (rather than a series of timestamped
events), with one chunk per mask-on slice. The previous assumption of only
a single event chunk per session meant that all events after the first slice
were getting dropped.
BiPAP AVAPS 30 (System One 60 Series) now works much better, although the data
doesn't yet show any gaps where the mask is off. Fixing that requires changes
throughout the code and not just in the PRS1 loader.
Also, LL calculation seems wrong. Perhaps the automatic calculation of
unintentional leak from total leak doesn't work for AVAPS, throwing off
automatic LL calculation? (F3V3 reports neither unintentional leakage nor
large leak events.)
This fixes the start/end times of such compliance sessions, but their
total_time is broken due to the presence of a 0-length slice.
That will require a more extensive fix of the slice system throughout
the program.
Also update the leak calculation logic to depend on the set of reported
events rather than hard-coding it based on machine family and version.
No change in functionality.