sopen_hl7aecg.c

来自「c++编写的用于生物信号处理的软件库」· C语言 代码 · 共 639 行 · 第 1/2 页

C
639
字号
/*    $Id: sopen_hl7aecg.c,v 1.17 2008/03/14 08:30:43 schloegl Exp $    Copyright (C) 2006,2007 Alois Schloegl <a.schloegl@ieee.org>    Copyright (C) 2007 Elias Apostolopoulos    This file is part of the "BioSig for C/C++" repository     (biosig4c++) at http://biosig.sf.net/     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 3    of the License, or (at your option) any later version. */#include <stdio.h>             // system includes#include <vector>#include <string>#include <sstream>#include "../biosig-dev.h"#include "../XMLParser/tinyxml.h"#include "../XMLParser/Tokenizer.h"int sopen_HL7aECG_read(HDRTYPE* hdr){/*	this function is a stub or placeholder and need to be defined in order to be useful.	It will be called by the function SOPEN in "biosig.c"	Input: 		char* Header	// contains the file content			Output: 		HDRTYPE *hdr	// defines the HDR structure accoring to "biosig.h"*/	char tmp[80]; 	TiXmlDocument doc(hdr->FileName);	if(doc.LoadFile()){	    TiXmlHandle hDoc(&doc);	    TiXmlHandle aECG = hDoc.FirstChild("AnnotatedECG");	    if(aECG.Element()){	    	char *strtmp = strdup(aECG.FirstChild("id").Element()->Attribute("root"));	    	size_t len = strlen(strtmp); 	    	if (len>MAX_LENGTH_RID)				fprintf(stdout,"Warning HL7aECG(read): length of Recording ID exceeds maximum length %i>%i\n",len,MAX_LENGTH_PID); 		strncpy(hdr->ID.Recording,strtmp,min(len,MAX_LENGTH_RID));		free(strtmp); 		TiXmlHandle effectiveTime = aECG.FirstChild("effectiveTime");		char *T0 = NULL;		if(effectiveTime.FirstChild("low").Element())		    T0 = (char *)effectiveTime.FirstChild("low").Element()->Attribute("value");		else if(effectiveTime.FirstChild("center").Element())		    T0 = (char *)effectiveTime.FirstChild("center").Element()->Attribute("value");		struct tm *t0 = (struct tm *)malloc(sizeof(struct tm));		T0[14] = '\0';		// ### ?FIXME?: compensate local time and DST in mktime used in tm_time2gdf_time below 		t0->tm_sec  = atoi(T0+12)-timezone;			T0[12] = '\0';		t0->tm_min  = atoi(T0+10);		T0[10] = '\0';		t0->tm_hour = atoi(T0+8);		T0[8]  = '\0';		t0->tm_mday = atoi(T0+6);		T0[6]  = '\0';		t0->tm_mon  = atoi(T0+4)-1;		T0[4]  = '\0';		t0->tm_year = atoi(T0)-1900;#ifndef __sparc__		t0->tm_gmtoff = 0;#endif		t0->tm_isdst  = -1; 		hdr->T0 = tm_time2gdf_time(t0);		TiXmlHandle demographic = aECG.FirstChild("componentOf").FirstChild("timepointEvent").FirstChild("componentOf").FirstChild("subjectAssignment").FirstChild("subject").FirstChild("trialSubject");		TiXmlElement *id = demographic.FirstChild("id").Element();		if(id) {			const char* tmpstr = id->Attribute("extension");			size_t len = strlen(tmpstr); 			if (len>MAX_LENGTH_PID)				fprintf(stdout,"Warning HL7aECG(read): length of Patient Id exceeds maximum length %i>%i\n",len,MAX_LENGTH_PID); 		    	strncpy(hdr->Patient.Id,tmpstr,MAX_LENGTH_PID);		}    		if (!hdr->FLAG.ANONYMOUS) 		{			demographic = demographic.FirstChild("subjectDemographicPerson");					TiXmlElement *name = demographic.FirstChild("name").Element();			if (name) {				size_t len = strlen(name->GetText());				if (len>MAX_LENGTH_NAME)					fprintf(stdout,"Warning HL7aECG(read): length of Patient Name exceeds maximum length %i>%i\n",len,MAX_LENGTH_PID); 				strncpy(hdr->Patient.Name, name->GetText(), MAX_LENGTH_NAME);			}				else				fprintf(stderr,"Warning: Patient Name could not be read.\n");		}				/* non-standard fields height and weight */		TiXmlElement *weight = demographic.FirstChild("weight").Element();		if (weight) {		    uint16_t code = PhysDimCode(strcpy(tmp,weight->Attribute("unit")));			    if ((code & 0xFFE0) != 1728) 		    	fprintf(stderr,"Warning: incorrect weight unit (%s)\n",weight->Attribute("unit"));			    else 	// convert to kilogram			hdr->Patient.Weight = uint8_t(atof(weight->Attribute("value"))*PhysDimScale(code)*1e-3);  		}		TiXmlElement *height = demographic.FirstChild("height").Element();		if (height) {		    uint16_t code = PhysDimCode(strcpy(tmp,height->Attribute("unit")));			    if ((code & 0xFFE0) != 1280) 		    	fprintf(stderr,"Warning: incorrect height unit (%s) %i \n",height->Attribute("unit"),code);			    else	// convert to centimeter			hdr->Patient.Height = uint8_t(atof(height->Attribute("value"))*PhysDimScale(code)*1e+2);		}				TiXmlElement *birthday = demographic.FirstChild("birthTime").Element();		if(birthday){		    T0 = (char *)birthday->Attribute("value");		    if (T0==NULL) T0=(char *)birthday->GetText();  // workaround for reading two different formats 		}		if (T0==NULL) 			;		else if (strlen(T0)>14) {		    T0[14] = '\0';		    t0->tm_sec = atoi(T0+12);		    T0[12] = '\0';		    t0->tm_min = atoi(T0+10);		    T0[10] = '\0';		    t0->tm_hour = atoi(T0+8);		    T0[8] = '\0';		    t0->tm_mday = atoi(T0+6);		    T0[6] = '\0';		    t0->tm_mon = atoi(T0+4)-1;		    T0[4] = '\0';		    t0->tm_year = atoi(T0)-1900;		    hdr->Patient.Birthday = tm_time2gdf_time(t0);		}//		else//		    fprintf(stderr,"Error: birthday\n");				TiXmlElement *sex = demographic.FirstChild("administrativeGenderCode").Element();		if(sex){		    if (sex->Attribute("code")==NULL)			hdr->Patient.Sex = 0;		    else if(!strcmp(sex->Attribute("code"),"F"))			hdr->Patient.Sex = 2;		    else if(!strcmp(sex->Attribute("code"),"M"))			hdr->Patient.Sex = 1;		    else			hdr->Patient.Sex = 0;		}else{		    hdr->Patient.Sex = 0;		}		int LowPass=0, HighPass=0, Notch=0;		TiXmlHandle channels = aECG.FirstChild("component").FirstChild("series").FirstChild("component").FirstChild("sequenceSet");		TiXmlHandle variables = aECG.FirstChild("component").FirstChild("series");		for(TiXmlElement *tmpvar = variables.FirstChild("controlVariable").Element(); tmpvar; tmpvar = tmpvar->NextSiblingElement("controlVariable")){		    if(!strcmp(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("code")->Attribute("code"), "MDC_ATTR_FILTER_NOTCH"))			Notch = atoi(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("component")->FirstChildElement("controlVariable")->FirstChildElement("value")->Attribute("value"));		    else if(!strcmp(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("code")->Attribute("code"), "MDC_ATTR_FILTER_LOW_PASS"))			LowPass = atoi(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("component")->FirstChildElement("controlVariable")->FirstChildElement("value")->Attribute("value"));		    else if(!strcmp(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("code")->Attribute("code"), "MDC_ATTR_FILTER_HIGH_PASS"))			HighPass = atoi(tmpvar->FirstChildElement("controlVariable")->FirstChildElement("component")->FirstChildElement("controlVariable")->FirstChildElement("value")->Attribute("value"));		}		hdr->NRec = 1;		hdr->SPR = 1;		hdr->AS.rawdata = (uint8_t *)malloc(hdr->SPR);		int32_t *data;				hdr->SampleRate = atof(channels.FirstChild("component").FirstChild("sequence").FirstChild("value").FirstChild("increment").Element()->Attribute("value"));				TiXmlHandle channel = channels.Child("component", 1).FirstChild("sequence");		for(hdr->NS = 0; channel.Element(); ++(hdr->NS), channel = channels.Child("component", hdr->NS+1).FirstChild("sequence"));		hdr->CHANNEL = (CHANNEL_TYPE*) calloc(hdr->NS,sizeof(CHANNEL_TYPE));		channel = channels.Child("component", 1).FirstChild("sequence");		for(int i = 0; channel.Element(); ++i, channel = channels.Child("component", i+1).FirstChild("sequence")){		    const char *code = channel.FirstChild("code").Element()->Attribute("code");		    		    strncpy(hdr->CHANNEL[i].Label,code,min(40,MAX_LENGTH_LABEL));		    hdr->CHANNEL[i].Transducer[0] = '\0';		    hdr->CHANNEL[i].GDFTYP = 5;	// int32		    std::vector<std::string> vector;		    stringtokenizer(vector, channel.FirstChild("value").FirstChild("digits").Element()->GetText());		    hdr->CHANNEL[i].SPR = vector.size();		    if (i==0) {		    	hdr->SPR = hdr->CHANNEL[i].SPR;			hdr->AS.rawdata = (uint8_t *)realloc(hdr->AS.rawdata, 4*(i+1)*hdr->NS*hdr->SPR*hdr->NRec);		    }		    else if (hdr->SPR != hdr->CHANNEL[i].SPR) {			fprintf(stderr,"Error: number of samples %i of #%i differ from %i in #0.\n",hdr->CHANNEL[i].SPR,i+1,hdr->SPR,1);			exit(-5);		    }			    /* read data samples */			    data = (int32_t*)(hdr->AS.rawdata + 4*i*(hdr->SPR));		    for(unsigned int j=0; j<hdr->SPR; ++j) {			data[j] = atoi(vector[j].c_str());			/* get Min/Max */			if(data[j] > hdr->CHANNEL[i].DigMax) {			    hdr->CHANNEL[i].DigMax = data[j];			}			if(data[j] < hdr->CHANNEL[i].DigMin){			    hdr->CHANNEL[i].DigMin = data[j];			}		    }		    /* scaling factors */ 		    hdr->CHANNEL[i].Cal  = atof(channel.FirstChild("value").FirstChild("scale").Element()->Attribute("value"));		    hdr->CHANNEL[i].Off  = atof(channel.FirstChild("value").FirstChild("origin").Element()->Attribute("value"));		    hdr->CHANNEL[i].DigMax += 1;		    hdr->CHANNEL[i].DigMin -= 1;		    hdr->CHANNEL[i].PhysMax = hdr->CHANNEL[i].DigMax*hdr->CHANNEL[i].Cal + hdr->CHANNEL[i].Off;		    hdr->CHANNEL[i].PhysMin = hdr->CHANNEL[i].DigMin*hdr->CHANNEL[i].Cal + hdr->CHANNEL[i].Off;		    /* Physical units */ 		    strncpy(tmp, channel.FirstChild("value").FirstChild("origin").Element()->Attribute("unit"),20); 		    hdr->CHANNEL[i].PhysDimCode = PhysDimCode(tmp); 		    		    hdr->CHANNEL[i].LowPass  = LowPass;		    hdr->CHANNEL[i].HighPass = HighPass;		    hdr->CHANNEL[i].Notch    = Notch;// 			hdr->CHANNEL[i].XYZ[0]   = l_endian_f32( *(float*) (Header2+ 4*k + 224*hdr->NS) );// 			hdr->CHANNEL[i].XYZ[1]   = l_endian_f32( *(float*) (Header2+ 4*k + 228*hdr->NS) );// 			hdr->CHANNEL[i].XYZ[2]   = l_endian_f32( *(float*) (Header2+ 4*k + 232*hdr->NS) );// 				//memcpy(&hdr->CHANNEL[k].XYZ,Header2 + 4*k + 224*hdr->NS,12);// 			hdr->CHANNEL[i].Impedance= ldexp(1.0, (uint8_t)Header2[k + 236*hdr->NS]/8);//		    hdr->CHANNEL[i].Impedance = INF;//		    for(int k1=0; k1<3; hdr->CHANNEL[index].XYZ[k1++] = 0.0);		}// hdr2ascii(hdr,stdout,2);	if (VERBOSE_LEVEL>8) fprintf(stdout,"[320] \n");			hdr->SampleRate *= hdr->SPR;		hdr->SampleRate  = hdr->SPR/hdr->SampleRate;		hdr->FLAG.OVERFLOWDETECTION = 0;	    }else{		fprintf(stderr, "%s : failed to parse (2)\n", hdr->FileName);	    }	}	else	    fprintf(stderr, "%s : failed to parse (1)\n", hdr->FileName);	return(0);};int sopen_HL7aECG_write(HDRTYPE* hdr){	size_t k;	for (k=0; k<hdr->NS; k++) {		hdr->CHANNEL[k].GDFTYP = 5; //int32	}	hdr->SPR *= hdr->NRec;	hdr->NRec = 1; 	hdr->FILE.OPEN=2;	return(0);};int sclose_HL7aECG_write(HDRTYPE* hdr){/*	this function is a stub or placeholder and need to be defined in order to be useful. 	It will be called by the function SOPEN in "biosig.c"	Input: HDR structure			Output: 		char* HDR.AS.Header 	// contains the content which will be written to the file in SOPEN*/	    char tmp[80];	    TiXmlDocument doc;        TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");    doc.LinkEndChild(decl);        TiXmlElement *root = new TiXmlElement("AnnotatedECG");    root->SetAttribute("xmlns", "urn:hl7-org:v3");    root->SetAttribute("xmlns:voc", "urn:hl7-org:v3/voc");    root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");    root->SetAttribute("xsi:schemaLocation", "urn:hl7-org:v3/HL7/aECG/2003-12/schema/PORT_MT020001.xsd");    root->SetAttribute("classCode", "OBS");    root->SetAttribute("moodCode", "EVN");    doc.LinkEndChild(root);    TiXmlElement *rootid = new TiXmlElement("id");    rootid->SetAttribute("root", strdup(hdr->ID.Recording));    root->LinkEndChild(rootid);	    TiXmlElement *rootCode = new TiXmlElement("code");    rootCode->SetAttribute("code", "93000");    rootCode->SetAttribute("codeSystem", "2.16.840.1.113883.6.12");    rootCode->SetAttribute("codeSystemName", "CPT-4");    root->LinkEndChild(rootCode);        char timelow[19], timehigh[19];    time_t T0 = gdf_time2t_time(hdr->T0);    struct tm *t0 = gmtime(&T0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?