mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
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.
748 lines
43 KiB
C++
748 lines
43 KiB
C++
/* Channel / Schema Implementation
|
|
*
|
|
* Copyright (c) 2019 The OSCAR Team
|
|
* Copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of the source code
|
|
* for more details. */
|
|
|
|
#include <QFile>
|
|
#include <QDebug>
|
|
#include <QDomDocument>
|
|
#include <QDomElement>
|
|
#include <QDomNode>
|
|
#include <QMessageBox>
|
|
#include <QApplication>
|
|
|
|
#include "common.h"
|
|
#include "schema.h"
|
|
#include "common_gui.h"
|
|
|
|
#include "SleepLib/profiles.h"
|
|
|
|
QColor adjustcolor(QColor color, float ar=1.0, float ag=1.0, float ab=1.0)
|
|
{
|
|
int r = color.red();
|
|
int g = color.green();
|
|
int b = color.blue();
|
|
|
|
r += rand() & 64;
|
|
g += rand() & 64;
|
|
b += rand() & 64;
|
|
|
|
r = qMin(int(r * ar), 255);
|
|
g = qMin(int(g * ag), 255);
|
|
b = qMin(int(b * ab), 255);
|
|
|
|
return QColor(r,g,b, color.alpha());
|
|
}
|
|
|
|
|
|
QColor darken(QColor color, float p);
|
|
|
|
namespace schema {
|
|
|
|
void resetChannels();
|
|
|
|
ChannelList channel;
|
|
Channel EmptyChannel;
|
|
Channel *SessionEnabledChannel;
|
|
|
|
QHash<QString, ChanType> ChanTypes;
|
|
QHash<QString, DataType> DataTypes;
|
|
QHash<QString, ScopeType> Scopes;
|
|
|
|
bool schema_initialized = false;
|
|
|
|
void setOrders() {
|
|
schema::channel[CPAP_PB].setOrder(1);
|
|
schema::channel[CPAP_CSR].setOrder(1);
|
|
schema::channel[CPAP_Ramp].setOrder(2);
|
|
schema::channel[CPAP_LargeLeak].setOrder(2);
|
|
schema::channel[CPAP_ClearAirway].setOrder(3);
|
|
schema::channel[CPAP_Obstructive].setOrder(4);
|
|
schema::channel[CPAP_Apnea].setOrder(4);
|
|
schema::channel[CPAP_NRI].setOrder(3);
|
|
schema::channel[CPAP_Hypopnea].setOrder(5);
|
|
schema::channel[CPAP_FlowLimit].setOrder(6);
|
|
schema::channel[CPAP_RERA].setOrder(6);
|
|
schema::channel[CPAP_VSnore].setOrder(7);
|
|
schema::channel[CPAP_VSnore2].setOrder(8);
|
|
schema::channel[CPAP_ExP].setOrder(6);
|
|
schema::channel[CPAP_UserFlag1].setOrder(256);
|
|
schema::channel[CPAP_UserFlag2].setOrder(257);
|
|
}
|
|
|
|
void init()
|
|
{
|
|
if (schema_initialized) { return; }
|
|
|
|
schema_initialized = true;
|
|
|
|
EmptyChannel = Channel(0, DATA, MT_UNKNOWN, DAY, "Empty", "Empty", "Empty Channel", "", "");
|
|
SessionEnabledChannel = new Channel(1, DATA, MT_UNKNOWN, DAY, "Enabled", "Enabled", "Session Enabled", "", "");
|
|
|
|
channel.channels[1] = SessionEnabledChannel;
|
|
channel.names["Enabled"] = SessionEnabledChannel;
|
|
SESSION_ENABLED = 1;
|
|
ChanTypes["data"] = DATA;
|
|
//Types["waveform"]=WAVEFORM;
|
|
ChanTypes["setting"] = SETTING;
|
|
|
|
Scopes["session"] = SESSION;
|
|
Scopes["day"] = DAY;
|
|
Scopes["machine"] = MACHINE;
|
|
Scopes["global"] = GLOBAL;
|
|
|
|
DataTypes[""] = DEFAULT;
|
|
DataTypes["bool"] = BOOL;
|
|
DataTypes["double"] = DOUBLE;
|
|
DataTypes["integer"] = INTEGER;
|
|
DataTypes["string"] = STRING;
|
|
DataTypes["richtext"] = RICHTEXT;
|
|
DataTypes["date"] = DATE;
|
|
DataTypes["datetime"] = DATETIME;
|
|
DataTypes["time"] = TIME;
|
|
|
|
// Note: Old channel names stored in channels.xml are not translatable.. they need to be moved to be defined AFTER here instead
|
|
if (!schema::channel.Load(":/docs/channels.xml")) {
|
|
QMessageBox::critical(0, STR_MessageBox_Error,
|
|
QObject::tr("Couldn't parse Channels.xml, this build is seriously borked, no choice but to abort!!"),
|
|
QMessageBox::Ok);
|
|
QApplication::exit(-1);
|
|
}
|
|
|
|
|
|
// Lookup Code strings are used internally and not meant to be translated
|
|
// Lookup Code strings are also used as a key to a graph of this channel
|
|
|
|
// Group ChannelID Code Type Scope Lookup Code Translable Name Description Shortened Name Units String FieldType Default Color
|
|
|
|
// Pressure Related Settings
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Pressure = 0x110C, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_Pressure, STR_TR_Pressure, QObject::tr("Therapy Pressure"), STR_TR_Pressure, STR_UNIT_CMH2O, DEFAULT, QColor("red")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_IPAP = 0x110D, WAVEFORM, MT_CPAP, SESSION, "IPAP", STR_TR_IPAP, QObject::tr("Inspiratory Pressure"), STR_TR_IPAP, STR_UNIT_CMH2O, DEFAULT, QColor("red")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_IPAPLo = 0x1110, WAVEFORM, MT_CPAP, SESSION, "IPAPLo", STR_TR_IPAPLo, QObject::tr("Lower Inspiratory Pressure"), STR_TR_IPAPLo, STR_UNIT_CMH2O, DEFAULT, QColor("orange")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_IPAPHi = 0x1111, WAVEFORM, MT_CPAP, SESSION, "IPAPHi", STR_TR_IPAPHi, QObject::tr("Higher Inspiratory Pressure"), STR_TR_IPAPHi, STR_UNIT_CMH2O, DEFAULT, QColor("orange")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAP = 0x110E, WAVEFORM, MT_CPAP, SESSION, "EPAP", STR_TR_EPAP, QObject::tr("Expiratory Pressure"), STR_TR_EPAP, STR_UNIT_CMH2O, DEFAULT, QColor("green")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAPLo = 0x111C, WAVEFORM, MT_CPAP, SESSION, "EPAPLo", STR_TR_EPAPLo, QObject::tr("Lower Expiratory Pressure"), STR_TR_EPAPLo, STR_UNIT_CMH2O, DEFAULT, QColor("light blue")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAPHi = 0x111D, WAVEFORM, MT_CPAP, SESSION, "EPAPHi", STR_TR_EPAPHi, QObject::tr("Higher Expiratory Pressure"), STR_TR_EPAPHi, STR_UNIT_CMH2O, DEFAULT, QColor("aqua")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PS = 0x110F, WAVEFORM, MT_CPAP, SESSION, "PS", STR_TR_PS, QObject::tr("Pressure Support"), STR_TR_PS, STR_UNIT_CMH2O, DEFAULT, QColor("grey")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PSMin = 0x111A, SETTING, MT_CPAP, SESSION, "PSMin", QObject::tr("PS Min") , QObject::tr("Pressure Support Minimum"), QObject::tr("PS Min"), STR_UNIT_CMH2O, DEFAULT, QColor("dark cyan")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PSMax = 0x111B, SETTING, MT_CPAP, SESSION, "PSMax", QObject::tr("PS Max"), QObject::tr("Pressure Support Maximum"), QObject::tr("PS Max"), STR_UNIT_CMH2O, DEFAULT, QColor("dark magenta")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PressureMin = 0x1020, SETTING, MT_CPAP, SESSION, "PressureMin", QObject::tr("Min Pressure"), QObject::tr("Minimum Therapy Pressure"), QObject::tr("Pressure Min"), STR_UNIT_CMH2O, DEFAULT, QColor("orange")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PressureMax = 0x1021, SETTING, MT_CPAP, SESSION, "PressureMax", QObject::tr("Max Pressure"), QObject::tr("Maximum Therapy Pressure"), QObject::tr("Pressure Max"), STR_UNIT_CMH2O, DEFAULT, QColor("light blue")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RampTime = 0x1022, SETTING, MT_CPAP, SESSION, "RampTime", QObject::tr("Ramp Time") , QObject::tr("Ramp Delay Period"), QObject::tr("Ramp Time"), STR_UNIT_Minutes, DEFAULT, QColor("black")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RampPressure = 0x1023, SETTING, MT_CPAP, SESSION, "RampPressure", QObject::tr("Ramp Pressure"), QObject::tr("Starting Ramp Pressure"), QObject::tr("Ramp Pressure"),STR_UNIT_CMH2O, DEFAULT, QColor("black")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Ramp = 0x1027, SPAN, MT_CPAP, SESSION, "Ramp", QObject::tr("Ramp Event") , QObject::tr("Ramp Event"), QObject::tr("Ramp"), STR_UNIT_EventsPerHour,DEFAULT, QColor("light blue")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PressureSet = 0x11A4, WAVEFORM, MT_CPAP, SESSION, "PressureSet", QObject::tr("Pressure Set"), QObject::tr("Pressure Setting"), QObject::tr("Pressure Set"), STR_UNIT_CMH2O, DEFAULT, QColor("dark red")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_IPAPSet = 0x11A5, WAVEFORM, MT_CPAP, SESSION, "IPAPSet", QObject::tr("IPAP Set"), QObject::tr("IPAP Setting"), QObject::tr("IPAP Set"), STR_UNIT_CMH2O, DEFAULT, QColor("dark red")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAPSet = 0x11A6, WAVEFORM, MT_CPAP, SESSION, "EPAPSet", QObject::tr("EPAP Set"), QObject::tr("EPAP Setting"), QObject::tr("EPAP Set"), STR_UNIT_CMH2O, DEFAULT, QColor("dark green")));
|
|
// Flags
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_CSR = 0x1000, SPAN, MT_CPAP, SESSION, "CSR",
|
|
QObject::tr("Cheyne Stokes Respiration"), QObject::tr("An abnormal period of Cheyne Stokes Respiration"), QObject::tr("CSR"), STR_UNIT_Percentage,DEFAULT, COLOR_CSR));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PB = 0x1028, SPAN, MT_CPAP, SESSION, "PB",
|
|
QObject::tr("Periodic Breathing"),QObject::tr("An abnormal period of Periodic Breathing"), QObject::tr("PB"),STR_UNIT_Percentage, DEFAULT, COLOR_CSR));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_ClearAirway = 0x1001, FLAG, MT_CPAP, SESSION, "ClearAirway",
|
|
QObject::tr("Clear Airway"), QObject::tr("An apnea where the airway is open"), QObject::tr("CA"), STR_UNIT_EventsPerHour, DEFAULT, QColor("purple")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Obstructive = 0x1002, FLAG, MT_CPAP, SESSION, "Obstructive",
|
|
QObject::tr("Obstructive"), QObject::tr("An apnea caused by airway obstruction"), QObject::tr("OA"), STR_UNIT_EventsPerHour, DEFAULT, QColor("#40c0ff")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Hypopnea = 0x1003, FLAG, MT_CPAP, SESSION, "Hypopnea",
|
|
QObject::tr("Hypopnea"), QObject::tr("A partially obstructed airway"), QObject::tr("H"), STR_UNIT_EventsPerHour, DEFAULT, QColor("blue")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Apnea = 0x1004, FLAG, MT_CPAP, SESSION, "Apnea",
|
|
QObject::tr("Unclassified Apnea"), QObject::tr("An apnea that couldn't be determined as Central or Obstructive."),QObject::tr("UA"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark green")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_FlowLimit = 0x1005, FLAG, MT_CPAP, SESSION, "FlowLimit",
|
|
QObject::tr("Flow Limitation"), QObject::tr("A restriction in breathing from normal, causing a flattening of the flow waveform."), QObject::tr("FL"), STR_UNIT_EventsPerHour, DEFAULT, QColor("#404040")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RERA = 0x1006, FLAG, MT_CPAP, SESSION, "RERA",
|
|
QObject::tr("RERA"),QObject::tr("Respiratory Effort Related Arousal: An restriction in breathing that causes an either an awakening or sleep disturbance."), QObject::tr("RE"), STR_UNIT_EventsPerHour, DEFAULT, COLOR_Gold));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_VSnore = 0x1007, FLAG, MT_CPAP, SESSION, "VSnore",
|
|
QObject::tr("Vibratory Snore"), QObject::tr("A vibratory snore"), QObject::tr("VS"), STR_UNIT_EventsPerHour, DEFAULT, QColor("red")));
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_VSnore2 = 0x1008, FLAG, MT_CPAP, SESSION, "VSnore2",
|
|
QObject::tr("Vibratory Snore (VS2) "),QObject::tr("A vibratory snore as detcted by a System One machine"),QObject::tr("VS2"), STR_UNIT_EventsPerHour, DEFAULT, QColor("red")));
|
|
// This Large Leak record is just a flag marker, used by Intellipap for one
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_LeakFlag = 0x100a, FLAG, MT_CPAP, SESSION, "LeakFlag",
|
|
QObject::tr("Leak Flag"), QObject::tr("A large mask leak affecting machine performance."), QObject::tr("LF"), STR_UNIT_EventsPerHour, DEFAULT, QColor("light gray")));
|
|
|
|
// The following is a Large Leak record that references a waveform span
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_LargeLeak = 0x1158, SPAN, MT_CPAP, SESSION, "LeakSpan",
|
|
QObject::tr("Large Leak"),QObject::tr("A large mask leak affecting machine performance."), QObject::tr("LL"), STR_UNIT_EventsPerHour, DEFAULT, QColor("light gray")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_NRI = 0x100b, FLAG, MT_CPAP, SESSION, "NRI",
|
|
QObject::tr("Non Responding Event"), QObject::tr("A type of respiratory event that won't respond to a pressure increase."), QObject::tr("NR"), STR_UNIT_EventsPerHour, DEFAULT, QColor("orange")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_ExP = 0x100c, FLAG, MT_CPAP, SESSION, "ExP",
|
|
QObject::tr("Expiratory Puff"), QObject::tr("Intellipap event where you breathe out your mouth."), QObject::tr("EP"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark magenta")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_SensAwake = 0x100d, FLAG, MT_CPAP, SESSION, "SensAwake",
|
|
QObject::tr("SensAwake"),QObject::tr("SensAwake feature will reduce pressure when waking is detected."),QObject::tr("SA"), STR_UNIT_EventsPerHour, DEFAULT, COLOR_Gold));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag1 = 0x101e, FLAG, MT_CPAP, SESSION, "UserFlag1",
|
|
QObject::tr("User Flag #1"), QObject::tr("A user definable event detected by OSCAR's flow waveform processor."), QObject::tr("UF1"), STR_UNIT_EventsPerHour, DEFAULT, QColor(0xc0,0xc0,0xe0)));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag2 = 0x101f, FLAG, MT_CPAP, SESSION, "UserFlag2",
|
|
QObject::tr("User Flag #2"),QObject::tr("A user definable event detected by OSCAR's flow waveform processor."), QObject::tr("UF2"), STR_UNIT_EventsPerHour, DEFAULT, QColor(0xa0,0xa0,0xc0)));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_UserFlag3 = 0x1024, FLAG, MT_CPAP, SESSION, "UserFlag3",
|
|
QObject::tr("User Flag #3"),QObject::tr("A user definable event detected by OSCAR's flow waveform processor."), QObject::tr("UF3"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark grey")));
|
|
|
|
// Oximetry
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_Pulse = 0x1800, WAVEFORM, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_Pulse,
|
|
QObject::tr("Pulse Rate"), QObject::tr("Heart rate in beats per minute"), QObject::tr("Pulse Rate"), STR_UNIT_BPM, DEFAULT, QColor("red")));
|
|
schema::channel[OXI_Pulse].setLowerThreshold(40);
|
|
schema::channel[OXI_Pulse].setUpperThreshold(130);
|
|
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_SPO2 = 0x1801, WAVEFORM, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_SPO2,
|
|
QObject::tr("SpO2 %"), QObject::tr("Blood-oxygen saturation percentage"), QObject::tr("SpO2"), STR_UNIT_Percentage, DEFAULT, QColor("blue")));
|
|
schema::channel[OXI_SPO2].setLowerThreshold(88);
|
|
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_Plethy = 0x1802, WAVEFORM, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_Plethy,
|
|
QObject::tr("Plethysomogram"), QObject::tr("An optical Photo-plethysomogram showing heart rhythm"), QObject::tr("Plethy"), STR_UNIT_Hz, DEFAULT, QColor("#404040")));
|
|
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_Perf = 0x1805, WAVEFORM, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_Perf,
|
|
QObject::tr("Perfusion Index"), QObject::tr("A relative assessment of the pulse strength at the monitoring site"), QObject::tr("Perf. Index %"), STR_UNIT_Percentage, DEFAULT, QColor("magenta")));
|
|
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_PulseChange = 0x1803, FLAG, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_PulseChange,
|
|
QObject::tr("Pulse Change"), QObject::tr("A sudden (user definable) change in heart rate"), QObject::tr("PC"), STR_UNIT_EventsPerHour, DEFAULT, QColor("light grey")));
|
|
|
|
schema::channel.add(GRP_OXI, new Channel(OXI_SPO2Drop = 0x1804, FLAG, MT_OXIMETER, SESSION, STR_GRAPH_Oxi_SPO2Drop,
|
|
QObject::tr("SpO2 Drop"), QObject::tr("A sudden (user definable) drop in blood oxygen saturation"), QObject::tr("SD"), STR_UNIT_EventsPerHour, DEFAULT, QColor("light blue")));
|
|
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_FlowRate = 0x1100, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_FlowRate,
|
|
QObject::tr("Flow Rate"), QObject::tr("Breathing flow rate waveform"), QObject::tr("Flow Rate"), STR_UNIT_LPM, DEFAULT, QColor("black")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_MaskPressure = 0x1101, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_MaskPressure,
|
|
QObject::tr("Mask Pressure"), QObject::tr("Mask Pressure"), QObject::tr("Mask Pressure"), STR_UNIT_CMH2O, DEFAULT, QColor("blue")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_MaskPressureHi = 0x1102, WAVEFORM, MT_CPAP, SESSION, "MaskPressureHi",
|
|
QObject::tr("Mask Pressure"), QObject::tr("Mask Pressure (High resolution)"), QObject::tr("Mask Pressure"), STR_UNIT_CMH2O, DEFAULT, QColor("blue"), 0x1101)); // linked to CPAP_MaskPressure
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_TidalVolume = 0x1103, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_TidalVolume,
|
|
QObject::tr("Tidal Volume"), QObject::tr("Amount of air displaced per breath"), QObject::tr("Tidal Volume"), STR_UNIT_ml, DEFAULT, QColor("magenta")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Snore = 0x1104, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_Snore,
|
|
QObject::tr("Snore"), QObject::tr("Graph displaying snore volume"), QObject::tr("Snore"), STR_UNIT_Unknown, DEFAULT, QColor("grey")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_MinuteVent = 0x1105, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_MinuteVent,
|
|
QObject::tr("Minute Ventilation"), QObject::tr("Amount of air displaced per minute"), QObject::tr("Minute Vent."), STR_UNIT_LPM, DEFAULT, QColor("dark cyan")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RespRate = 0x1106, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_RespRate,
|
|
QObject::tr("Respiratory Rate"), QObject::tr("Rate of breaths per minute"), QObject::tr("Resp. Rate"), STR_UNIT_BreathsPerMinute, DEFAULT, QColor("dark magenta")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_PTB = 0x1107, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_PTB,
|
|
QObject::tr("Patient Triggered Breaths"), QObject::tr("Percentage of breaths triggered by patient"), QObject::tr("Pat. Trig. Breaths"), STR_UNIT_Percentage, DEFAULT, QColor("dark grey")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Leak = 0x1108, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_LeakRate,
|
|
QObject::tr("Leak Rate"), QObject::tr("Rate of detected mask leakage"), QObject::tr("Leak Rate"), STR_UNIT_LPM, DEFAULT, QColor("dark green")));
|
|
schema::channel[CPAP_Leak].setLowerThreshold(24.0);
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_IE = 0x1109, WAVEFORM, MT_CPAP, SESSION, "IE",
|
|
QObject::tr("I:E Ratio"), QObject::tr("Ratio between Inspiratory and Expiratory time"), QObject::tr("I:E Ratio"), STR_UNIT_Ratio, DEFAULT, QColor("dark red")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Te = 0x110A, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_Te,
|
|
QObject::tr("Expiratory Time"), QObject::tr("Time taken to breathe out"), QObject::tr("Exp. Time"), STR_UNIT_Seconds, DEFAULT, QColor("dark green")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_Ti = 0x110B, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_Ti,
|
|
QObject::tr("Inspiratory Time"), QObject::tr("Time taken to breathe in"), QObject::tr("Insp. Time"), STR_UNIT_Seconds, DEFAULT, QColor("dark blue")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RespEvent = 0x1112, DATA, MT_CPAP, SESSION, STR_GRAPH_RespEvent,
|
|
QObject::tr("Respiratory Event"), QObject::tr("A ResMed data source showing Respiratory Events"), QObject::tr("Resp. Event"), STR_UNIT_EventsPerHour, DEFAULT, QColor("black")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_FLG = 0x1113, WAVEFORM, MT_CPAP, SESSION, STR_GRAPH_FlowLimitation,
|
|
QObject::tr("Flow Limitation"), QObject::tr("Graph showing severity of flow limitations"), QObject::tr("Flow Limit."), STR_UNIT_Severity, DEFAULT, QColor("#585858")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_TgMV = 0x1114, WAVEFORM, MT_CPAP, SESSION, "TgMV",
|
|
QObject::tr("Target Minute Ventilation"), QObject::tr("Target Minute Ventilation"), QObject::tr("Target Vent."), STR_UNIT_LPM, DEFAULT, QColor("dark red")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_MaxLeak = 0x1115, WAVEFORM, MT_CPAP, SESSION, "MaxLeak",
|
|
QObject::tr("Maximum Leak"), QObject::tr("The maximum rate of mask leakage"), QObject::tr("Max Leaks"), STR_UNIT_LPM, DEFAULT, QColor("dark red")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_AHI = 0x1116, WAVEFORM, MT_CPAP, SESSION, "AHI",
|
|
QObject::tr("Apnea Hypopnea Index"), QObject::tr("Graph showing running AHI for the past hour"), QObject::tr("AHI"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark red")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_LeakTotal = 0x1117, WAVEFORM, MT_CPAP, SESSION, "LeakTotal",
|
|
QObject::tr("Total Leak Rate"), QObject::tr("Detected mask leakage including natural Mask leakages"), QObject::tr("Total Leaks"), STR_UNIT_LPM, DEFAULT, QColor("dark green")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_LeakMedian = 0x1118, WAVEFORM, MT_CPAP, SESSION, "LeakMedian",
|
|
QObject::tr("Median Leak Rate"), QObject::tr("Median rate of detected mask leakage"), QObject::tr("Median Leaks"), STR_UNIT_LPM, DEFAULT, QColor("dark green")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_RDI = 0x1119, WAVEFORM, MT_CPAP, SESSION, "RDI",
|
|
QObject::tr("Respiratory Disturbance Index"), QObject::tr("Graph showing running RDI for the past hour"), QObject::tr("RDI"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark red")));
|
|
|
|
// Positional sensors
|
|
schema::channel.add(GRP_POS, new Channel(POS_Orientation = 0x2990, WAVEFORM, MT_POSITION, SESSION, STR_GRAPH_Orientation,
|
|
QObject::tr("Orientation"), QObject::tr("Sleep position in degrees"), QObject::tr("Orientation"), STR_UNIT_Degrees, DEFAULT, QColor("dark blue")));
|
|
|
|
schema::channel.add(GRP_POS, new Channel(POS_Inclination = 0x2991, WAVEFORM, MT_POSITION, SESSION, STR_GRAPH_Inclination,
|
|
QObject::tr("Inclination"), QObject::tr("Upright angle in degrees"), QObject::tr("Inclination"), STR_UNIT_Degrees, DEFAULT, QColor("dark magenta")));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(RMS9_MaskOnTime = 0x1025, DATA, MT_CPAP, SESSION, "MaskOnTime",
|
|
QObject::tr("Mask On Time"), QObject::tr("Time started according to str.edf"), QObject::tr("Mask On Time"), STR_UNIT_Unknown, DEFAULT, Qt::black));
|
|
|
|
schema::channel.add(GRP_CPAP, new Channel(CPAP_SummaryOnly = 0x1026, DATA, MT_CPAP, SESSION, "SummaryOnly",
|
|
QObject::tr("Summary Only"), QObject::tr("CPAP Session contains summary data only"), QObject::tr("Summary Only"), STR_UNIT_Unknown, DEFAULT, Qt::black));
|
|
|
|
Channel *ch;
|
|
schema::channel.add(GRP_CPAP, ch = new Channel(CPAP_Mode = 0x1200, SETTING, MT_CPAP, SESSION, "PAPMode",
|
|
QObject::tr("PAP Mode"), QObject::tr("PAP Device Mode"), QObject::tr("PAP Mode"), QString(), LOOKUP, Qt::black));
|
|
|
|
ch->addOption(0, STR_TR_Unknown);
|
|
ch->addOption(1, STR_TR_CPAP);
|
|
ch->addOption(2, QObject::tr("APAP (Variable)"));
|
|
ch->addOption(3, QObject::tr("Fixed Bi-Level"));
|
|
ch->addOption(4, QObject::tr("Auto Bi-Level (Fixed PS)"));
|
|
ch->addOption(5, QObject::tr("Auto Bi-Level (Variable PS)"));
|
|
ch->addOption(6, QObject::tr("ASV (Fixed EPAP)"));
|
|
ch->addOption(7, QObject::tr("ASV (Variable EPAP)"));
|
|
ch->addOption(8, QObject::tr("AVAPS"));
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Old Journal system crap
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Journal_Weight = 0x0803, DATA, MT_JOURNAL, DAY, "Weight", QObject::tr("Weight"), QObject::tr("Weight"), QObject::tr("Weight"), STR_UNIT_KG, DOUBLE, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(0x0804, DATA, MT_JOURNAL, DAY, "Height", QObject::tr("Height"), QObject::tr("Physical Height"), QObject::tr("Height"), STR_UNIT_CM, DOUBLE, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Bookmark_Notes=0x0805, DATA, MT_JOURNAL, DAY, "BookmarkNotes", QObject::tr("Notes"), QObject::tr("Bookmark Notes"), QObject::tr("Notes"), QString(), STRING, Qt::black));
|
|
// This may as well be calculated
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Journal_BMI = 0x0806, DATA, MT_JOURNAL, DAY, "BMI", QObject::tr("BMI"), QObject::tr("Body Mass Index"), QObject::tr("BMI"), QString(), DOUBLE, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Journal_ZombieMeter = 0x0807, DATA, MT_JOURNAL, DAY, "ZombieMeter", QObject::tr("Zombie"), QObject::tr("How you feel (0 = like crap, 10 = unstoppable)"), QObject::tr("Zombie"), QString(), DOUBLE, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Bookmark_Start=0x0808, DATA, MT_JOURNAL, DAY, "BookmarkStart", QObject::tr("Start"), QObject::tr("Bookmark Start"), QObject::tr("Start"), QString(), INTEGER, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Bookmark_End=0x0809, DATA, MT_JOURNAL, DAY, "BookmarkEnd", QObject::tr("End"), QObject::tr("Bookmark End"), QObject::tr("End"), QString(), DOUBLE, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(LastUpdated=0x080a, DATA, MT_JOURNAL, DAY, "LastUpdated", QObject::tr("Last Updated"), QObject::tr("Last Updated"), QObject::tr("Last Updated"), QString(), DATETIME, Qt::black));
|
|
schema::channel.add(GRP_JOURNAL, ch = new Channel(Journal_Notes = 0xd000, DATA, MT_JOURNAL, DAY, "Journal", QObject::tr("Journal Notes"), QObject::tr("Journal Notes"), QObject::tr("Journal"), QString(), RICHTEXT, Qt::black));
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Sleep Stage Channels
|
|
//////////////////////////////////////////////////////////////////////
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_SleepStage = 0x2000, WAVEFORM, MT_SLEEPSTAGE, SESSION, "SleepStage",
|
|
QObject::tr("Sleep Stage"), QObject::tr("1=Awake 2=REM 3=Light Sleep 4=Deep Sleep"), QObject::tr("Sleep Stage"), QString(), INTEGER, Qt::darkGray));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(0x2001, WAVEFORM, MT_SLEEPSTAGE, SESSION, "ZeoBW",
|
|
QObject::tr("Brain Wave"), QObject::tr("Brain Wave"), QObject::tr("BrainWave"), QString(), INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_Awakenings = 0x2002, DATA, MT_SLEEPSTAGE, SESSION, "Awakenings", QObject::tr("Awakenings"), QObject::tr("Number of Awakenings"), QObject::tr("Awakenings"), QString(), INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_MorningFeel= 0x2003, DATA, MT_SLEEPSTAGE, SESSION, "MorningFeel", QObject::tr("Morning Feel"), QObject::tr("How you felt in the morning"), QObject::tr("Morning Feel"), QString(), INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_TimeInWake = 0x2004, DATA, MT_SLEEPSTAGE, SESSION, "TimeInWake", QObject::tr("Time Awake"), QObject::tr("Time spent awake"), QObject::tr("Time Awake"), STR_UNIT_Minutes, INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_TimeInREM = 0x2005, DATA, MT_SLEEPSTAGE, SESSION, "TimeInREM", QObject::tr("Time In REM Sleep"), QObject::tr("Time spent in REM Sleep"), QObject::tr("Time in REM Sleep"), STR_UNIT_Minutes, INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_TimeInLight= 0x2006, DATA, MT_SLEEPSTAGE, SESSION, "TimeInLight",QObject::tr("Time In Light Sleep"), QObject::tr("Time spent in light sleep"), QObject::tr("Time in Light Sleep"), STR_UNIT_Minutes, INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_TimeInDeep = 0x2007, DATA, MT_SLEEPSTAGE, SESSION, "TimeInDeep", QObject::tr("Time In Deep Sleep"), QObject::tr("Time spent in deep sleep"), QObject::tr("Time in Deep Sleep"), STR_UNIT_Minutes, INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_TimeInDeep = 0x2008, DATA, MT_SLEEPSTAGE, SESSION, "TimeToZ", QObject::tr("Time to Sleep"), QObject::tr("Time taken to get to sleep"), QObject::tr("Time to Sleep"), STR_UNIT_Minutes, INTEGER, Qt::black));
|
|
schema::channel.add(GRP_SLEEP, ch = new Channel(ZEO_ZQ = 0x2009, DATA, MT_SLEEPSTAGE, SESSION, "ZeoZQ", QObject::tr("Zeo ZQ"), QObject::tr("Zeo sleep quality measurement"), QObject::tr("ZEO ZQ"), QString(), INTEGER, Qt::black));
|
|
|
|
NoChannel = 0;
|
|
CPAP_BrokenSummary = schema::channel["BrokenSummary"].id();
|
|
CPAP_BrokenWaveform = schema::channel["BrokenWaveform"].id();
|
|
|
|
// <channel id="0x111e" class="data" name="TestChan1" details="Debugging Channel #2" label="Test #1" unit="" color="pink"/>
|
|
// <channel id="0x111f" class="data" name="TestChan2" details="Debugging Channel #2" label="Test #2" unit="" color="blue"/>
|
|
|
|
schema::channel.add(GRP_CPAP, ch=new Channel(CPAP_Test1 = 0x111e, DATA, MT_CPAP, SESSION, STR_GRAPH_TestChan1, QObject::tr("Debugging channel #1"), QObject::tr("Top secret internal stuff you're not supposed to see ;)"), QObject::tr("Test #1"), QString(), INTEGER, QColor("pink")));
|
|
schema::channel.add(GRP_CPAP, ch=new Channel(CPAP_Test2 = 0x111f, DATA, MT_CPAP, SESSION, STR_GRAPH_TestChan2, QObject::tr("Debugging channel #2"), QObject::tr("Top secret internal stuff you're not supposed to see ;)"), QObject::tr("Test #2"), QString(), INTEGER, Qt::blue));
|
|
|
|
RMS9_E01 = schema::channel["RMS9_E01"].id();
|
|
RMS9_E02 = schema::channel["RMS9_E02"].id();
|
|
RMS9_SetPressure = schema::channel["SetPressure"].id(); // TODO: this isn't needed anymore
|
|
CPAP_HumidSetting = schema::channel["HumidSet"].id();
|
|
INTELLIPAP_Unknown1 = schema::channel["IntUnk1"].id();
|
|
INTELLIPAP_Unknown2 = schema::channel["IntUnk2"].id();
|
|
|
|
schema::channel[CPAP_Leak].setShowInOverview(true);
|
|
schema::channel[CPAP_RespRate].setShowInOverview(true);
|
|
schema::channel[CPAP_MinuteVent].setShowInOverview(true);
|
|
schema::channel[CPAP_TidalVolume].setShowInOverview(true);
|
|
schema::channel[CPAP_CSR].setShowInOverview(true);
|
|
schema::channel[CPAP_PB].setShowInOverview(true);
|
|
schema::channel[CPAP_LargeLeak].setShowInOverview(true);
|
|
schema::channel[CPAP_FLG].setShowInOverview(true);
|
|
}
|
|
|
|
|
|
void resetChannels()
|
|
{
|
|
schema::channel.channels.clear();
|
|
schema::channel.names.clear();
|
|
schema::channel.groups.clear();
|
|
|
|
schema_initialized = false;
|
|
init();
|
|
|
|
QList<MachineLoader *> list = GetLoaders();
|
|
for (int i=0; i< list.size(); ++i) {
|
|
MachineLoader * loader = list.at(i);
|
|
loader->initChannels();
|
|
}
|
|
setOrders();
|
|
}
|
|
|
|
Channel::Channel(ChannelID id, ChanType type, MachineType machtype, ScopeType scope, QString code, QString fullname,
|
|
QString description, QString label, QString unit, DataType datatype, QColor color, int link):
|
|
m_id(id),
|
|
m_type(type),
|
|
m_machtype(machtype),
|
|
m_scope(scope),
|
|
m_code(code),
|
|
m_fullname(fullname),
|
|
m_description(description),
|
|
m_label(label),
|
|
m_unit(unit),
|
|
m_datatype(datatype),
|
|
m_defaultcolor(color),
|
|
m_link(link),
|
|
m_upperThreshold(0),
|
|
m_lowerThreshold(0),
|
|
m_upperThresholdColor(Qt::red),
|
|
m_lowerThresholdColor(Qt::green),
|
|
m_enabled(true),
|
|
m_order(255)
|
|
{
|
|
if (type == WAVEFORM) {
|
|
calc[Calc_Min] = ChannelCalc(id, Calc_Min, adjustcolor(color, 0.25f, 1.0f, 1.3f), false);
|
|
calc[Calc_Middle] = ChannelCalc(id, Calc_Middle, adjustcolor(color, 1.3f, 1.0f, 1.0f), false);
|
|
calc[Calc_Perc] = ChannelCalc(id, Calc_Perc, adjustcolor(color, 1.1f, 1.2f, 1.0f), false);
|
|
calc[Calc_Max] = ChannelCalc(id, Calc_Max, adjustcolor(color, 0.5f, 1.2f, 1.0f), false);
|
|
calc[Calc_Zero] = ChannelCalc(id, Calc_Zero, Qt::red, false);
|
|
calc[Calc_LowerThresh] = ChannelCalc(id, Calc_LowerThresh, Qt::blue, false);
|
|
calc[Calc_UpperThresh] = ChannelCalc(id, Calc_UpperThresh, Qt::red, false);
|
|
}
|
|
m_showInOverview = false;
|
|
|
|
default_fullname = fullname;
|
|
default_label = label;
|
|
default_description = description;
|
|
|
|
}
|
|
bool Channel::isNull()
|
|
{
|
|
return (this == &EmptyChannel);
|
|
}
|
|
|
|
ChannelList::ChannelList()
|
|
: m_doctype("channels")
|
|
{
|
|
}
|
|
ChannelList::~ChannelList()
|
|
{
|
|
for (auto & chan : channels) {
|
|
delete chan;
|
|
}
|
|
}
|
|
bool ChannelList::Load(QString filename)
|
|
{
|
|
QDomDocument doc(m_doctype);
|
|
QFile file(filename);
|
|
qDebug() << "Opening " << filename;
|
|
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
qWarning() << "Could not open" << filename;
|
|
return false;
|
|
}
|
|
|
|
QString errorMsg;
|
|
int errorLine;
|
|
|
|
if (!doc.setContent(&file, false, &errorMsg, &errorLine)) {
|
|
qWarning() << "Invalid XML Content in" << filename;
|
|
qWarning() << "Error line" << errorLine << ":" << errorMsg;
|
|
return false;
|
|
}
|
|
|
|
file.close();
|
|
|
|
|
|
QDomElement root = doc.documentElement();
|
|
|
|
if (root.tagName().toLower() != "channels") {
|
|
return false;
|
|
}
|
|
|
|
QString language = root.attribute("language", "en");
|
|
QString version = root.attribute("version", "");
|
|
|
|
if (version.isEmpty()) {
|
|
qWarning() << "No Version Field in" << m_doctype << "Schema, assuming 1.0" << filename;
|
|
version = "1.0";
|
|
}
|
|
|
|
qDebug() << "Processing xml file:" << m_doctype << language << version;
|
|
QDomNodeList grp = root.elementsByTagName("group");
|
|
QDomNode node, n, ch;
|
|
QDomElement e;
|
|
|
|
bool ok;
|
|
int id, linkid;
|
|
QString chantype, scopestr, typestr, name, group, idtxt, details, label, unit, datatypestr, defcolor, link;
|
|
ChanType type;
|
|
DataType datatype;
|
|
Channel *chan;
|
|
QColor color;
|
|
//bool multi;
|
|
ScopeType scope;
|
|
int line;
|
|
|
|
for (int i = 0; i < grp.size(); i++) {
|
|
node = grp.at(i);
|
|
group = node.toElement().attribute("name");
|
|
//qDebug() << "Group Name" << group;
|
|
// Why do I have to skip the first node here? (shows up empty)
|
|
n = node.firstChildElement();
|
|
|
|
while (!n.isNull()) {
|
|
line = n.lineNumber();
|
|
e = n.toElement();
|
|
|
|
if (e.nodeName().toLower() != "channel") {
|
|
qWarning() << "Ignoring unrecognized schema type " << e.nodeName() << "in" << filename << "line" <<
|
|
line;
|
|
continue;
|
|
}
|
|
|
|
ch = n.firstChild();
|
|
n = n.nextSibling();
|
|
|
|
idtxt = e.attribute("id");
|
|
id = idtxt.toInt(&ok, 16);
|
|
|
|
if (!ok) {
|
|
qWarning() << "Dodgy ID number " << e.nodeName() << "in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
chantype = e.attribute("class", "data").toLower();
|
|
|
|
if (!ChanTypes.contains(chantype)) {
|
|
qWarning() << "Dodgy class " << chantype << "in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
type = ChanTypes[chantype];
|
|
|
|
scopestr = e.attribute("scope", "session");
|
|
|
|
if (scopestr.at(0) == QChar('!')) {
|
|
scopestr = scopestr.mid(1);
|
|
//multi=true;
|
|
} //multi=false;
|
|
|
|
if (!Scopes.contains(scopestr)) {
|
|
qWarning() << "Dodgy Scope " << scopestr << "in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
scope = Scopes[scopestr];
|
|
|
|
name = e.attribute("name", "");
|
|
details = e.attribute("details", "");
|
|
label = e.attribute("label", "");
|
|
|
|
if (name.isEmpty() || details.isEmpty() || label.isEmpty()) {
|
|
qWarning() << "Missing name,details or label attribute in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
unit = e.attribute("unit");
|
|
|
|
defcolor = e.attribute("color", "black");
|
|
color = QColor(defcolor);
|
|
|
|
if (!color.isValid()) {
|
|
qWarning() << "Invalid Color " << defcolor << "in" << filename << "line" << line;
|
|
color = Qt::black;
|
|
}
|
|
|
|
datatypestr = e.attribute("type", "").toLower();
|
|
|
|
link = e.attribute("link", "");
|
|
|
|
if (!link.isEmpty()) {
|
|
linkid = link.toInt(&ok, 16);
|
|
|
|
if (!ok) {
|
|
qWarning() << "Dodgy Link ID number " << e.nodeName() << "in" << filename << " line" << line;
|
|
}
|
|
} else { linkid = 0; }
|
|
|
|
if (DataTypes.contains(datatypestr)) {
|
|
datatype = DataTypes[typestr];
|
|
} else {
|
|
qWarning() << "Ignoring unrecognized schema datatype in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
if (channels.contains(id)) {
|
|
qWarning() << "Schema already contains id" << id << "in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
if (names.contains(name)) {
|
|
qWarning() << "Schema already contains name" << name << "in" << filename << "line" << line;
|
|
continue;
|
|
}
|
|
|
|
chan = new Channel(id, type, MT_UNKNOWN, scope, name, name, details, label, unit, datatype, color, linkid);
|
|
channels[id] = chan;
|
|
names[name] = chan;
|
|
//qDebug() << "Channel" << id << name << label;
|
|
groups[group][name] = chan;
|
|
|
|
if (linkid > 0) {
|
|
if (channels.contains(linkid)) {
|
|
Channel *it = channels[linkid];
|
|
it->m_links.push_back(chan);
|
|
//int i=0;
|
|
} else {
|
|
qWarning() << "Linked channel" << name << ":" << linkid << "should be defined first in" << filename << "line" << line;
|
|
}
|
|
}
|
|
|
|
// process children
|
|
while (!ch.isNull()) {
|
|
e = ch.toElement();
|
|
QString sub = ch.nodeName().toLower();
|
|
QString id2str, name2str;
|
|
int id2;
|
|
|
|
if (sub == "option") {
|
|
id2str = e.attribute("id");
|
|
id2 = id2str.toInt(&ok, 10);
|
|
name2str = e.attribute("value");
|
|
//qDebug() << sub << id2 << name2str;
|
|
chan->addOption(id2, name2str);
|
|
} else if (sub == "color") {
|
|
}
|
|
|
|
ch = ch.nextSibling();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ChannelList::add(QString group, Channel *chan)
|
|
{
|
|
if (chan == nullptr) {
|
|
qCritical() << "ChannelList::add called with null chan object";
|
|
return;
|
|
}
|
|
|
|
if (channels.contains(chan->id())) {
|
|
qCritical() << "Channels already contains id" << chan->id() << chan->code();
|
|
return;
|
|
}
|
|
|
|
if (names.contains(chan->code())) {
|
|
qCritical() << "Channels already contains name" << chan->id() << chan->code();
|
|
return;
|
|
}
|
|
|
|
channels[chan->id()] = chan;
|
|
names[chan->code()] = chan;
|
|
groups[group][chan->code()] = chan;
|
|
|
|
if (channels.contains(chan->linkid())) {
|
|
Channel *it = channels[chan->linkid()];
|
|
it->m_links.push_back(chan);
|
|
//int i=0;
|
|
} else {
|
|
if (chan->linkid()>0) {
|
|
qWarning() << "Linked channel must be defined first for" << chan->code();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ChannelList::Save(QString filename)
|
|
{
|
|
if (filename.isEmpty())
|
|
return false;
|
|
|
|
qDebug() << "In ChannelList::Save() saving " << filename;;
|
|
|
|
QDomDocument doc("channels");
|
|
|
|
QDomElement droot = doc.createElement(STR_AppName);
|
|
doc.appendChild(droot);
|
|
|
|
QDomElement root = doc.createElement("channels");
|
|
droot.appendChild(root);
|
|
|
|
|
|
for (auto git=groups.begin(), end=groups.end(); git != end; ++git) {
|
|
auto & chanlist = git.value();
|
|
|
|
QDomElement grp = doc.createElement("group");
|
|
grp.setAttribute("name", git.key());
|
|
root.appendChild(grp);
|
|
for (auto it = chanlist.begin(), cend=chanlist.end(); it!=cend; ++it) {
|
|
Channel * chan = it.value();
|
|
QDomElement cn = doc.createElement("channel");
|
|
cn.setAttribute("id", chan->id());
|
|
cn.setAttribute("code", it.key());
|
|
cn.setAttribute("label", chan->label());
|
|
cn.setAttribute("name", chan->fullname());
|
|
cn.setAttribute("description", chan->description());
|
|
cn.setAttribute("color", chan->defaultColor().name());
|
|
cn.setAttribute("upper", chan->upperThreshold());
|
|
cn.setAttribute("lower", chan->lowerThreshold());
|
|
cn.setAttribute("order", chan->order());
|
|
cn.setAttribute("type", chan->type());
|
|
cn.setAttribute("datatype", chan->datatype());
|
|
cn.setAttribute("overview", chan->showInOverview());
|
|
for (auto op=chan->m_options.begin(), opend=chan->m_options.end(); op!=opend; ++op) {
|
|
QDomElement c2 = doc.createElement("option");
|
|
c2.setAttribute("key", op.key());
|
|
c2.setAttribute("value", op.value());
|
|
cn.appendChild(c2);
|
|
}
|
|
|
|
//cn.appendChild(doc.createTextNode(i.value().toDateTime().toString("yyyy-MM-dd HH:mm:ss")));
|
|
grp.appendChild(cn);
|
|
}
|
|
}
|
|
|
|
QFile file(filename);
|
|
|
|
if (!file.open(QIODevice::WriteOnly)) {
|
|
return false;
|
|
}
|
|
|
|
QTextStream ts(&file);
|
|
ts << doc.toString();
|
|
file.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
QString ChannelCalc::label()
|
|
{
|
|
QString lab = schema::channel[code].label();
|
|
QString m_label;
|
|
switch(type) {
|
|
case Calc_Min:
|
|
m_label = QString("%1 %2").arg(STR_TR_Min).arg(lab);
|
|
break;
|
|
case Calc_Middle:
|
|
m_label = Day::calcMiddleLabel(code);
|
|
break;
|
|
case Calc_Perc:
|
|
m_label = Day::calcPercentileLabel(code);
|
|
break;
|
|
case Calc_Max:
|
|
m_label = Day::calcMaxLabel(code);
|
|
break;
|
|
case Calc_Zero:
|
|
m_label = QObject::tr("Zero");
|
|
break;
|
|
case Calc_UpperThresh:
|
|
m_label = QString("%1 %2").arg(lab).arg(QObject::tr("Upper Threshold"));
|
|
break;
|
|
case Calc_LowerThresh:
|
|
m_label = QString("%1 %2").arg(lab).arg(QObject::tr("Lower Threshold"));
|
|
break;
|
|
}
|
|
return m_label;
|
|
|
|
}
|
|
|
|
//typedef schema::Channel * ChannelID;
|