/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cvgateway.h" #include "carevue.h" #include "logfile.h" #include "exception.h" #include #include "ORUmsg.h" #include "ACKmsg.h" #include "LabEventInfo.h" #include "Unit.h" #include "xios.h" /****************************************************************** * RESULT REPORT */ bool convert_obx(ORUmsg::GRPgrp::OBRgrp::OBXgrp&, STtyp&); void valtostr(IDtyp&, double x, u_int, u_int); HL7Message *report_results(HL7Message &msg) { ORUmsg &request = (ORUmsg &)msg; ORUmsg cv_req; cv_req.MesHea = request.MesHea; cv_req.MesHea.RecApp = "CLI"; LabEventInfo lei_cache; ACKmsg *ack = NULL; for(repstruc *rgrp = &request.GRPgroup; !rgrp->end(); rgrp = rgrp->next()) { ORUmsg::GRPgrp &grp = rgrp->first(); if(grp.PIDgroup.ispresent) { // NOTE: CareVue doesn't like PV1 segments in ORU cv_req.GRPgroup[0].PIDgroup.PatIde = grp.PIDgroup.PatIde; fix_pid(cv_req.GRPgroup[0].PIDgroup.PatIde, grp.PIDgroup.PatVisit); } // Cycle through OBR segments for(repstruc *robr = &grp.OBRgroup; !robr->end(); robr = robr->next()) { cv_req.GRPgroup[0].OBRgroup[0] = robr->first(); ORUmsg::GRPgrp::OBRgrp &obr = cv_req.GRPgroup[0].OBRgroup[0]; if(!obr.ObsReq.SpeRecDateTime.ispresent()) obr.ObsReq.SpeRecDateTime.set(); if(!obr.ObsReq.ObsDateTime.ispresent()) obr.ObsReq.ObsDateTime = obr.ObsReq.SpeRecDateTime; obr.ObsReq.ResStatus = obrrsc2hp(obr.ObsReq.ResStatus); // Cycle through OBX segments int sid = 0; for(repstruc *robx = &obr.OBXgroup; !robx->end(); robx = robx->next()) { ORUmsg::GRPgrp::OBRgrp::OBXgrp &obx = robx->first(); obx.Obs.SetIdObsSim = ++sid; // Abnormal Flags for(repfield *rabf = &obx.Obs.AbnFlags; !rabf->end(); rabf = rabf->next()) { AbnFlagsCode &abf = rabf->first(); if(abf == AbnFlagsCode::_LTval || abf == AbnFlagsCode::_GTval) { strstream notes; xios _xnotes(notes); if(abf == AbnFlagsCode::_LTval) notes << "Der wahre Wert ist kleiner (ABL: `<"; if(abf == AbnFlagsCode::_GTval) notes << "Der wahre Wert ist groesser (ABL: `>"; notes << hl7er << obx.Obs.ObsValue << " " << obx.Obs.Units.Ide << "')" << ends; obx.NotesAndCom.prepend(); obx.NotesAndCom[0].SetIdNotesAndCom = 1; obx.NotesAndCom[0].SouOfCom = SouOfComCode::Pval; obx.NotesAndCom[0].Com[0] = notes.str(); notes.freeze(0); } abf = abf2hp(abf); } if(convert_obx(obx, obr.ObsReq.SpeSou.Com1)) { // append the OBR NTE to each OBX NTE // FIXME: RepeatBase class needs a CONC method for(repstruc *rnte = &obr.NotesAndCom; !rnte->end(); rnte = rnte->next()) obx.NotesAndCom.append(rnte->first()); // fix notes and comments: // - only one NTE segment per OBX // - only one NTE comment per NTE NTEseg nte; for(repstruc *rnte = &obx.NotesAndCom; !rnte->end(); rnte = rnte->next()) for(repfield *rcom = &(rnte->first().Com); !rcom->end(); rcom = rcom->next()) { nte.Com[0] += rcom->first(); nte.Com[0] += ". "; } obx.NotesAndCom.unset(); obx.NotesAndCom[0] = nte; } else obx.unset(); } if(obr.ObsReq.SpeSou.Com1 == "BLD" || obr.ObsReq.SpeSou.Com1 == "BLDA" || obr.ObsReq.SpeSou.Com1 == "BLDC") { ORUmsg::GRPgrp::OBRgrp::OBXgrp &obx = obr.OBXgroup[sid]; obx.Obs.SetIdObsSim = ++sid; obx.Obs.ValueType = DataTypeCode::STval; obx.Obs.ObsIde.Ide = "BGATYPA"; if(obr.ObsReq.SpeSou.Com1 == "BLDA") obx.Obs.ObsValue = "art"; else if(obr.ObsReq.SpeSou.Com1 == "BLDC") obx.Obs.ObsValue = "cap"; else obx.Obs.ObsValue = "unbek."; obx.Obs.AbnFlags[0] = AbnFlagsCode::Nval; obx.Obs.ObsResStatus = ObsResStatusCodesIntCode::Sval; } else if(obr.ObsReq.SpeSou.Com1 == "BLDV" || obr.ObsReq.SpeSou.Com1 == "BLDVM") { ORUmsg::GRPgrp::OBRgrp::OBXgrp &obx = obr.OBXgroup[sid]; obx.Obs.SetIdObsSim = ++sid; obx.Obs.ValueType = DataTypeCode::STval; obx.Obs.ObsIde.Ide = "BGATYPV"; if(obr.ObsReq.SpeSou.Com1 == "BLDVM") obx.Obs.ObsValue = "gem.ven"; else obx.Obs.ObsValue = "unbek."; obx.Obs.AbnFlags[0] = AbnFlagsCode::Nval; obx.Obs.ObsResStatus = ObsResStatusCodesIntCode::Sval; } if(ack != NULL) delete ack; ack = (ACKmsg *)forward_message(cv_req); if(ack->MesAck.Ack != AckCode::AAval && ack->MesAck.Ack != AckCode::CAval) return ack; } // OBR group } // GRP group return ack; } bool convert_obx(ORUmsg::GRPgrp::OBRgrp::OBXgrp &obx, STtyp &ssrc) { if(!obx.Obs.ObsValue.ispresent() || obx.Obs.ObsValue.isnull()) return FALSE; obx.Obs.ObsResStatus = obxrsc2hp(obx.Obs.ObsResStatus); if(obx.Obs.ValueType == DataTypeCode::NMval) { LabEventInfo lei; lookup_again: if(lei.lookup(obx.Obs.ObsIde.Ide)) { // make group the Patient Temperature to BLDA or BLDV if(strcmp(lei.getProperty(),"*BGATEMP*") == 0) { if(ssrc == "BLDA" || ssrc == "BLDC" || ssrc == "BLD") obx.Obs.ObsIde.Ide = "BGATEMPA"; else if(ssrc == "BLDV" || ssrc == "BLDVM") obx.Obs.ObsIde.Ide = "BGATEMPV"; else FATAL("we shouldn't be here!"); goto lookup_again; } NMtyp val(obx.Obs.ObsValue); Unit unit1(obx.Obs.Units.Ide); Unit unit2; if(lei.getUnit() != NULL && *lei.getUnit() != '\0') unit2 = lei.getUnit(); double rval = (double)val; // range checking bool norm_rc = lei.getLowNormal() != lei.getHighNormal(); bool alert_rc = lei.getLowAlert() != lei.getHighAlert(); bool limit_rc = lei.getMinValue() != lei.getMaxValue(); if(unit1 != unit2) { if(dim(unit1) == dim(unit2)) // commensurable units? rval = convert(rval, unit1, unit2); else if(lei.getConstVal() != 0) // do we have a constant? { Unit cunit(lei.getConstUnit()); double cval = lei.getConstVal(); Unit runit; // determine use of constant // remember that if u and v are units then // dim(u * v) = dim(u) + dim(v) // and dim(u / v) = dim(u) - dim(v) if(dim(unit1) + dim(cunit) == dim(unit2)) { rval = rval * cval; runit = unit1 * cunit; } else if(dim(unit1) - dim(cunit) == dim(unit2)) { rval = rval / cval; runit = unit1 / cunit; } else // no way! goto conversion_failed; rval = convert(rval, runit, unit2); } else goto conversion_failed; obx.Obs.Units.Ide = unit2; valtostr(obx.Obs.ObsValue, rval, val.getPrecision(),7); } else { valtostr(obx.Obs.ObsValue, rval, val.getPrecision(),7); } if(limit_rc && rval < lei.getMinValue()) { ostrstream err; err << "Der Wert " << (const char*)obx.Obs.ObsValue << " " << (const char*)unit2; if(unit1 != unit2) err << " (" << (const char *)STtyp(val) << " " << (const char *)unit1 << ")"; err << " unterschreitet den fuer CareVue " "configurierten Minimalwert " << lei.getMinValue() << " " << lei.getUnit() << ends; LOGWARNING("%s", err.str()); obx.NotesAndCom.append().Com[0] += err.str(); err.freeze(0); valtostr(obx.Obs.ObsValue, lei.getMinValue(), lei.getPrecision(),7); obx.Obs.AbnFlags.prepend(AbnFlagsCode::Aval); return TRUE; } else if(limit_rc && rval > lei.getMaxValue()) { ostrstream err; err << "Der Wert " << (const char*)obx.Obs.ObsValue << " " << (const char*)unit2; if(unit1 != unit2) err << " (" << (const char *)STtyp(val) << " " << (const char *)unit1 << ")"; err << " ueberschreitet den fuer CareVue " "configurierten Maximalwert " << lei.getMaxValue() << " " << lei.getUnit() << ends; LOGWARNING("%s", err.str()); obx.NotesAndCom.append().Com[0] += err.str(); err.freeze(0); valtostr(obx.Obs.ObsValue, lei.getMaxValue(), lei.getPrecision(),7); obx.Obs.AbnFlags.prepend(AbnFlagsCode::Aval); return TRUE; } else if(alert_rc && rval < lei.getLowAlert()) obx.Obs.AbnFlags.prepend(AbnFlagsCode::Lval); else if(alert_rc && rval > lei.getHighAlert()) obx.Obs.AbnFlags.prepend(AbnFlagsCode::Lval); else if(norm_rc && rval < lei.getLowNormal()) obx.Obs.AbnFlags.prepend(AbnFlagsCode::Aval); else if(norm_rc && rval > lei.getHighNormal()) obx.Obs.AbnFlags.prepend(AbnFlagsCode::Aval); else obx.Obs.AbnFlags.append(AbnFlagsCode::Nval); obx.Obs.ValueType = DataTypeCode::STval; return TRUE; conversion_failed: { // we have been unable to convert the measure ostrstream err; err << "Der Wert " << (const char*)obx.Obs.ObsValue << " " << (const char*)unit1 << " konnte nicht in die Einheit " << lei.getUnit() << " konvertiert werden" << ends; LOGWARNING("%s", err.str()); obx.NotesAndCom.append().Com[0] = err.str(); err.freeze(0); obx.Obs.ObsValue = lei.getMinValue(); obx.Obs.AbnFlags.prepend(AbnFlagsCode::Aval); obx.Obs.ValueType = DataTypeCode::STval; obx.Obs.ObsResStatus = obxrsc2hp(obx.Obs.ObsResStatus); return TRUE; } } else { char *ce = obx.Obs.ObsIde.o2str(); LOGINFO("could not find `%s' in lei", ce); delete [] ce; return FALSE; } } else return FALSE; } void valtostr(IDtyp &s, double x, u_int prec, u_int len) { prec++; ostrstream os; if(prec > len - 1) prec = len - 1; os.precision(prec); os << x << '\0'; s = os.str(); os.freeze(0); } #include "adt_obx.cc" // workaround for a compiler/linker problem