mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
Convert compliance "slices" to events with a starting delta.
Also fix the related enums and add more value checks. Also add YAML output of the cumulative mask-on slice time.
This commit is contained in:
parent
a6455b6b05
commit
1a0a4bbf52
@ -896,10 +896,10 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion &
|
||||
|
||||
float s2 = double(slice.end - slice.start) / 3600000.0;
|
||||
|
||||
QColor col = (slice.status == EquipmentOn) ? goodcolor : Qt::black;
|
||||
QColor col = (slice.status == MaskOn) ? goodcolor : Qt::black;
|
||||
QString txt = QObject::tr("%1\nLength: %3\nStart: %2\n").arg(datestr).arg(st.time().toString("hh:mm:ss")).arg(s2,0,'f',2);
|
||||
|
||||
txt += (slice.status == EquipmentOn) ? QObject::tr("Mask On") : QObject::tr("Mask Off");
|
||||
txt += (slice.status == MaskOn) ? QObject::tr("Mask On") : QObject::tr("Mask Off");
|
||||
slices.append(SummaryChartSlice(&calcitems[0], s1, s2, txt, col));
|
||||
}
|
||||
} else {
|
||||
|
@ -657,7 +657,7 @@ qint64 Day::total_time()
|
||||
}
|
||||
} else {
|
||||
for (auto & slice : sess->m_slices) {
|
||||
if (slice.status == EquipmentOn) {
|
||||
if (slice.status == MaskOn) {
|
||||
range.insert(slice.start, 0);
|
||||
range.insert(slice.end, 1);
|
||||
d_totaltime += slice.end - slice.start;
|
||||
@ -727,7 +727,7 @@ qint64 Day::total_time(MachineType type)
|
||||
}
|
||||
} else {
|
||||
for (const auto & slice : sess->m_slices) {
|
||||
if (slice.status == EquipmentOn) {
|
||||
if (slice.status == MaskOn) {
|
||||
range.insert(slice.start, 0);
|
||||
range.insert(slice.end, 1);
|
||||
d_totaltime += slice.end - slice.start;
|
||||
|
@ -1384,19 +1384,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class PRS1ParsedSliceEvent : public PRS1ParsedDurationEvent
|
||||
class PRS1ParsedSliceEvent : public PRS1ParsedValueEvent
|
||||
{
|
||||
public:
|
||||
virtual QMap<QString,QString> contents(void)
|
||||
{
|
||||
QMap<QString,QString> out;
|
||||
out["start"] = timeStr(m_start);
|
||||
out["duration"] = timeStr(m_duration);
|
||||
QString s;
|
||||
switch (m_status) {
|
||||
case EquipmentOn: s = "EquipmentOn"; break;
|
||||
switch ((SliceStatus) m_value) {
|
||||
case MaskOn: s = "MaskOn"; break;
|
||||
case MaskOff: s = "MaskOff"; break;
|
||||
case EquipmentOff: s = "EquipmentOff"; break;
|
||||
case EquipmentLeaking: s = "EquipmentLeaking"; break;
|
||||
case UnknownStatus: s = "Unknown"; break;
|
||||
}
|
||||
out["status"] = s;
|
||||
@ -1404,9 +1403,8 @@ public:
|
||||
}
|
||||
|
||||
static const PRS1ParsedEventType TYPE = EV_PRS1_SLICE;
|
||||
SliceStatus m_status;
|
||||
|
||||
PRS1ParsedSliceEvent(int start, int duration, SliceStatus status) : PRS1ParsedDurationEvent(TYPE, start, duration), m_status(status) {}
|
||||
PRS1ParsedSliceEvent(int start, SliceStatus status) : PRS1ParsedValueEvent(TYPE, start, (int) status) {}
|
||||
};
|
||||
|
||||
|
||||
@ -3169,8 +3167,11 @@ bool PRS1Import::ImportCompliance()
|
||||
if (e->m_type == PRS1ParsedSliceEvent::TYPE) {
|
||||
PRS1ParsedSliceEvent* s = (PRS1ParsedSliceEvent*) e;
|
||||
qint64 tt = start + qint64(s->m_start) * 1000L;
|
||||
qint64 duration = qint64(s->m_duration) * 1000L;
|
||||
session->m_slices.append(SessionSlice(tt, tt + duration, s->m_status));
|
||||
if (!session->m_slices.isEmpty()) {
|
||||
SessionSlice & prevSlice = session->m_slices.last();
|
||||
prevSlice.end = tt;
|
||||
}
|
||||
session->m_slices.append(SessionSlice(tt, tt, (SliceStatus) s->m_value));
|
||||
continue;
|
||||
} else if (e->m_type != PRS1ParsedSettingEvent::TYPE) {
|
||||
qWarning() << "Compliance had non-setting event:" << (int) e->m_type;
|
||||
@ -3267,9 +3268,6 @@ bool PRS1DataChunk::ParseCompliance(void)
|
||||
CHECK_VALUE(data[0x0b], 1);
|
||||
CHECK_VALUE(data[0x0c], 0);
|
||||
CHECK_VALUE(data[0x0d], 0);
|
||||
CHECK_VALUE(data[0x0e], 2);
|
||||
CHECK_VALUE(data[0x0f], 0);
|
||||
CHECK_VALUE(data[0x10], 0);
|
||||
|
||||
// TODO: What are slices, and why would only bricks have them? That seems very weird.
|
||||
|
||||
@ -3281,31 +3279,32 @@ bool PRS1DataChunk::ParseCompliance(void)
|
||||
int tt = start;
|
||||
|
||||
int len = this->size()-3;
|
||||
int pos = 0x11;
|
||||
int pos = 0x0e;
|
||||
do {
|
||||
quint8 c = data[pos++];
|
||||
// TODO: This isn't duration, it's a start time! Why else would an EquipmentOff
|
||||
// slice have a nonzero value here? In one session, there's a big black span
|
||||
// during which the machine is counting blower time but not usage, corresponding
|
||||
// to the EquipmentOff delta. So these aren't slices with durations, they're events
|
||||
// with a delta offset!
|
||||
int duration = data[pos] | data[pos+1] << 8;
|
||||
// These aren't really slices as originally thought, they're events with a delta offset.
|
||||
// We'll convert them to slices in the importer.
|
||||
int delta = data[pos] | data[pos+1] << 8;
|
||||
pos+=2;
|
||||
SliceStatus status;
|
||||
if (c == 0x03) {
|
||||
status = EquipmentOn;
|
||||
} else if (c == 0x02) {
|
||||
status = EquipmentLeaking;
|
||||
if (c == 0x02) {
|
||||
status = MaskOn;
|
||||
if (tt == 0) {
|
||||
CHECK_VALUE(delta, 0); // we've never seen the initial MaskOn have any delta
|
||||
} else {
|
||||
if (delta % 60) UNEXPECTED_VALUE(delta, "even minutes"); // mask-off events seem to be whole minutes?
|
||||
}
|
||||
} else if (c == 0x03) {
|
||||
status = MaskOff;
|
||||
} else if (c == 0x01) {
|
||||
status = EquipmentOff;
|
||||
CHECK_VALUE(duration, 0);
|
||||
// This has a delta if the mask was removed before the machine was shut off.
|
||||
} else {
|
||||
qDebug() << this->sessionid << "unknown slice status" << c;
|
||||
break;
|
||||
}
|
||||
this->AddEvent(new PRS1ParsedSliceEvent(tt, duration, status));
|
||||
|
||||
tt += duration;
|
||||
tt += delta;
|
||||
this->AddEvent(new PRS1ParsedSliceEvent(tt, status));
|
||||
} while (pos < len);
|
||||
|
||||
// also seems to be a trailing 01 00 81 after the slices?
|
||||
@ -3563,6 +3562,8 @@ void PRS1DataChunk::ParseFlexSetting(quint8 flex, CPAPMode cpapmode)
|
||||
// c0 Split CFlex then None
|
||||
// c8 Split CFlex+ then None
|
||||
|
||||
if (flex & (0x20 | 0x04)) UNEXPECTED_VALUE(flex, "known bits");
|
||||
|
||||
flex &= 0xf8;
|
||||
bool split = false;
|
||||
|
||||
@ -3591,11 +3592,18 @@ void PRS1DataChunk::ParseFlexSetting(quint8 flex, CPAPMode cpapmode)
|
||||
|
||||
void PRS1DataChunk::ParseHumidifierSetting(int humid, bool supportsHeatedTubing)
|
||||
{
|
||||
if (humid & (0x40 | 0x20 | 0x08)) UNEXPECTED_VALUE(humid, "known bits");
|
||||
|
||||
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, (humid & 0x80) != 0)); // Humidifier Connected
|
||||
if (supportsHeatedTubing) {
|
||||
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBING, (humid & 0x10) != 0)); // Heated Hose??
|
||||
} else {
|
||||
CHECK_VALUE(humid & 0x10, 0);
|
||||
}
|
||||
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, (humid & 7))); // Humidifier Value
|
||||
int humidlevel = humid & 7;
|
||||
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); // Humidifier Value
|
||||
|
||||
if (humidlevel > 5) UNEXPECTED_VALUE(humidlevel, "<= 5");
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
class Machine;
|
||||
|
||||
enum SliceStatus {
|
||||
UnknownStatus=0, EquipmentOff, EquipmentLeaking, EquipmentOn
|
||||
UnknownStatus=0, EquipmentOff, MaskOn, MaskOff // is there an EquipmentOn?
|
||||
};
|
||||
|
||||
class SessionSlice
|
||||
@ -137,7 +137,7 @@ class Session
|
||||
// t = 0;
|
||||
// for (int i=0; i<size; ++i) {
|
||||
// const SessionSlice & slice = m_slices.at(i);
|
||||
// if (slice.status == EquipmentOn) {
|
||||
// if (slice.status == MaskOn) {
|
||||
// t += slice.end - slice.start;
|
||||
// }
|
||||
// }
|
||||
@ -187,7 +187,7 @@ class Session
|
||||
t = 0;
|
||||
for (int i=0; i<size; ++i) {
|
||||
const SessionSlice & slice = m_slices.at(i);
|
||||
if (slice.status == EquipmentOn) {
|
||||
if (slice.status == MaskOn) {
|
||||
t += slice.end - slice.start;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,17 @@ static QString hex(int i)
|
||||
return QString("0x") + QString::number(i, 16).toUpper();
|
||||
}
|
||||
|
||||
static QString dur(qint64 msecs)
|
||||
{
|
||||
qint64 s = msecs / 1000L;
|
||||
int h = s / 3600; s -= h * 3600;
|
||||
int m = s / 60; s -= m * 60;
|
||||
return QString("%1:%2:%3")
|
||||
.arg(h, 2, 10, QChar('0'))
|
||||
.arg(m, 2, 10, QChar('0'))
|
||||
.arg(s, 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
#define ENUMSTRING(ENUM) case ENUM: s = #ENUM; break
|
||||
static QString eventListTypeName(EventListType t)
|
||||
{
|
||||
@ -171,6 +182,11 @@ void SessionToYaml(QString filepath, Session* session)
|
||||
out << " start: " << ts(session->first()) << endl;
|
||||
out << " end: " << ts(session->last()) << endl;
|
||||
|
||||
Day day;
|
||||
day.addSession(session);
|
||||
out << " total_time: " << dur(day.total_time()) << endl;
|
||||
day.removeSession(session);
|
||||
|
||||
out << " settings:" << endl;
|
||||
|
||||
// We can't get deterministic ordering from QHash iterators, so we need to create a list
|
||||
|
Loading…
Reference in New Issue
Block a user