Advertisement
Guest User

Untitled

a guest
Apr 26th, 2018
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.38 KB | None | 0 0
  1. using Microsoft.WindowsAzure.Storage.Queue;
  2. using Newtonsoft.Json;
  3. using Newtonsoft.Json.Linq;
  4. using QueueProcessor.DataObjects;
  5. using SironaFilesProcessor;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Data;
  9. using System.Drawing;
  10. using System.IO;
  11. using System.IO.Compression;
  12. using System.Linq;
  13. using System.Net.Http;
  14. using System.Security.AccessControl;
  15. using System.Text;
  16. using System.Threading.Tasks;
  17. using System.Windows.Forms.DataVisualization.Charting;
  18.  
  19. namespace QueueProcessor
  20. {
  21. class PhysionetEventParser
  22. {
  23.  
  24. public static async Task ProcessFiles(String message)
  25. {
  26. bool AtrCorrupted = false;
  27. //Create a temp direcotry in the Web root path
  28. var tempGuid = Guid.NewGuid().ToString();
  29. var tempFolder = (Environment.GetEnvironmentVariable("WEBROOT_PATH") ?? @"C:/users/public") + "/" + tempGuid;
  30.  
  31. //Download event files to local directory previously created
  32. var storageContext = new StorageContext();
  33. // Get and create the container
  34. var studiesContainer = storageContext.BlobClient.GetContainerReference("studies");
  35. studiesContainer.CreateIfNotExists();
  36. Directory.CreateDirectory(tempFolder);
  37. var studyId = int.Parse(message.Split('_')[1]);
  38. //var tryingBlob = studiesContainer.GetAppendBlobReference(studyId + "/queuelog.txt");
  39. //if (!await tryingBlob.ExistsAsync())
  40. //{
  41. // await tryingBlob.CreateOrReplaceAsync();
  42. //}
  43. //using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, ("Before Try: " + message)) + Environment.NewLine)))
  44. //{
  45. // await tryingBlob.AppendBlockAsync(ms);
  46.  
  47. //}
  48. var rawFileName = message.Split('/')[message.Split('/').Length - 1];
  49. var blobName = message;
  50.  
  51. try
  52. {
  53.  
  54. #region Donwloading files from blobs to local directory
  55.  
  56. var blob = studiesContainer.GetBlockBlobReference(blobName + ".hea");
  57. if (blob.Exists())
  58. {
  59. await blob.DownloadToFileAsync(tempFolder + "/" + rawFileName + ".hea", FileMode.OpenOrCreate);
  60. }
  61.  
  62. blob = studiesContainer.GetBlockBlobReference(blobName + ".json");
  63. if (blob.Exists())
  64. {
  65. await blob.DownloadToFileAsync(tempFolder + "/" + rawFileName + ".json", FileMode.OpenOrCreate);
  66. }
  67.  
  68. blob = studiesContainer.GetBlockBlobReference(blobName + ".dat");
  69. if (blob.Exists())
  70. {
  71. await blob.DownloadToFileAsync(tempFolder + "/" + rawFileName + ".dat", FileMode.OpenOrCreate);
  72. }
  73.  
  74. blob = studiesContainer.GetBlockBlobReference(blobName + ".atr");
  75. if (blob.Exists())
  76. {
  77. await blob.DownloadToFileAsync(tempFolder + "/" + rawFileName + ".atr", FileMode.OpenOrCreate);
  78. }
  79.  
  80. #endregion
  81.  
  82. #region Processing Files
  83.  
  84.  
  85. //To check if the device and the study are valid here before processing any data
  86. var deviceSN = rawFileName.Split('_')[0];
  87. TimeSpan UTCValue = new TimeSpan();
  88. using (var context = new LifeSenseDBEntities())
  89. {
  90. var device = context.Devices.FirstOrDefault(o => o.SerialNumber == deviceSN && (o.Deleted == null || o.Deleted != true));
  91. if (device != null)
  92. {
  93. //Get the running or started study attached to the device
  94. var study = context.Studies.FirstOrDefault(o => o.DeviceId == device.Id && o.StatusId != 3);
  95. if (study != null)
  96. {
  97. study.LastActivity = DateTime.UtcNow;
  98. var recordName = rawFileName;
  99. //Parse the JSON file in order to map the event to its study and save it in the db
  100. //var jsonText = File.ReadAllText(tempFolderPath + "/" + fileName + "/" + recordName + ".json");
  101. //JObject jSonObject = JObject.Parse(jsonText);
  102. //JObject deviceInfo = (JObject)jSonObject["Device"];
  103.  
  104. ////This field is called device ID by the manufacturer, though it refers to serial number in our number
  105. //var deviceId = (string)deviceInfo["Device ID"];
  106.  
  107. //JObject patientInfo = (JObject)jSonObject["Patient"];
  108.  
  109. ////PatientId on the mobile App is the Study ID in CloudBeat system
  110. //var patientId = (string)patientInfo["Patient ID"];
  111. //var patientFirstName = (string)patientInfo["Patient First Name"];
  112. //var patientMiddleName = (string)patientInfo["Patient Middle Initial"];
  113. //var patientLastName = (string)patientInfo["Patient Last Name"];
  114. //var patientPhysicianName = (string)patientInfo["Physician Name"];
  115.  
  116. //JObject timeInfo = (JObject)jSonObject["Time"];
  117. //var procedureStartTime = (string)timeInfo["Procedure Start Time"];
  118. //var stripStartTime = (string)timeInfo["Strip Start Time"];
  119. //var stripLength = (string)timeInfo["Strip Length"];
  120. //var transmitTime = (string)timeInfo["Transmit Time"];
  121.  
  122. //Parse the header file
  123. string[] lines = System.IO.File.ReadAllLines(tempFolder + "/" + recordName + ".hea");
  124.  
  125. //Get Record Line Data (first line)
  126. var recordLineParams = lines[0].Split(' ');
  127.  
  128. var recordNameInHeader = recordLineParams[0];
  129. var numberOfSignals = recordLineParams[1];
  130. int samplingFrequency = 250;
  131. int.TryParse(recordLineParams[2], out samplingFrequency);
  132.  
  133. var numberOfSamplesPerSignal = recordLineParams[3]; //If it is zero or missing, the number of samples is unspecified
  134. var baseTime = recordLineParams[4]; //It gives the time of day that corresponds to the beginning of the record, in HH:MM:SS format
  135. var baseDate = recordLineParams[5]; //It contains the date that corresponds to the beginning of the record, in DD/MM/YYYY format
  136.  
  137.  
  138. var gain = 102.4;
  139. if (int.Parse(numberOfSignals) >= 1)
  140. {
  141. var firstSignaleLine = lines[1];
  142. var firstSignalLineParts = firstSignaleLine.Split(' ');
  143. if (firstSignalLineParts.Length > 2)
  144. {
  145. var success = Double.TryParse(firstSignalLineParts[2], out gain);
  146. if (!success)
  147. {
  148. gain = 102.4;
  149. }
  150. }
  151. }
  152. //Parsing the json file to get the eventtype
  153. string jsonFile = File.ReadAllText(tempFolder + "/" + recordName + ".json");
  154. string eventType = "";
  155. string StripLength = "";
  156. DateTime StripDate = new DateTime();
  157. if (jsonFile != null)
  158. {
  159. JObject Body = JsonConvert.DeserializeObject<JObject>(jsonFile, new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None });
  160. JObject timeInfo = (JObject)Body["Time"];
  161. eventType = (string)timeInfo["Event type"];
  162. var StripStartTime = (string)timeInfo["Strip Start Time"];
  163. StripLength = (string)timeInfo["Strip Length"];
  164. var dateTimeOffset = DateTimeOffset.Parse(StripStartTime, null);
  165. StripDate = dateTimeOffset.DateTime;
  166. UTCValue = dateTimeOffset.Offset;
  167.  
  168. }
  169.  
  170. /* string eventType = "Undefined";
  171. var commentsLine = "";
  172.  
  173. if (lines.Length > 1 + int.Parse(numberOfSignals))
  174. {
  175. commentsLine = lines[1 + int.Parse(numberOfSignals)].ToLower();
  176. }
  177.  
  178. if (commentsLine.Contains("manual"))
  179. {
  180. eventType = "Patient Triggered";
  181. }
  182. else if (commentsLine.Contains("automatic"))
  183. {
  184. var evType = commentsLine.Replace(" ", "").Split('-')[1].ToLower();
  185. var eventsMapper = context.PhysionetEventMappers.FirstOrDefault(o => o.DeviceEventType.ToLower() == evType);
  186. if (eventsMapper != null)
  187. {
  188. eventType = context.EventsTypes.FirstOrDefault(o => o.Id == eventsMapper.CBEventTypeId).Description;
  189. }
  190. else
  191. {
  192. eventType = "Undefined";
  193. }
  194.  
  195. }
  196. */
  197.  
  198.  
  199. //Name, Type and Description will be the same
  200. switch (eventType)
  201. {
  202. case "Request":
  203. eventType = "Server Data Request";
  204. break;
  205. case "Automatic - BRADY":
  206. eventType = "Bradycardia";
  207. break;
  208. case "Automatic - TACHY":
  209. eventType = "Tachycardia";
  210. break;
  211. case "Automatic - PAUSE":
  212. eventType = "Pause Event";
  213. break;
  214. case "Manual":
  215. eventType = "Patient Triggered";
  216. break;
  217. case "Automatic - ARRHYTHMIA_AF":
  218. eventType = "Atrial Fibrillation";
  219. break;
  220. default:
  221. break;
  222. }
  223.  
  224. if (eventType != "Server Data Request")
  225. {
  226. var newEvent = new Event();
  227. newEvent.StudyId = study.Id;
  228.  
  229. newEvent.Name = eventType;
  230. newEvent.Type = eventType;
  231. newEvent.Description = eventType;
  232.  
  233. //Parse the data file to convert it into CSV and store at the right place according to the study id.
  234. //Note here that for the time this parser has created, the signals data must be in the same .dat file
  235.  
  236.  
  237. SByteParser.ParseSironaECG(tempFolder + "/" + recordName + ".dat", numberOfSignals);
  238.  
  239.  
  240. //ToDo: Change the type, name and description
  241. if (File.Exists(tempFolder + "/" + recordName + ".atr"))
  242. {
  243. SByteParser.ParseSironaAnnotation(tempFolder + "/" + recordName + ".atr");
  244. }
  245.  
  246.  
  247. //var eventMonitorSettings = context.EventMonitorSettings.FirstOrDefault(o => o.StudyId == study.Id);
  248. //if (eventMonitorSettings != null)
  249. //{
  250.  
  251.  
  252. //}
  253. //else
  254. //{
  255. // newEvent.EventOccurredAtSample = 0;
  256. //}
  257.  
  258. //The default number of samples is the worth of 3 minutes
  259. int numberofsamples = samplingFrequency * int.Parse(StripLength);
  260. //int.TryParse(numberOfSamplesPerSignal, out numberofsamples);
  261.  
  262. //If we have 1.5 minutes to get NumberOfECGFiles = 2
  263. newEvent.NumberOfECGFiles = (int)Math.Ceiling((double)numberofsamples / (60 * samplingFrequency));
  264.  
  265. if (device.DeviceTypeId == 6)
  266. {
  267. //Get the Pre and Post defined in the header
  268. //They are set in seconds, so change time to samples to know when the event occured
  269. string[] PrePost = lines[int.Parse(numberOfSignals) + 2].Split(' ');
  270. var Pre = PrePost[2];
  271. var Post = PrePost[4];
  272. var PreInSamples = int.Parse(Pre) * samplingFrequency;
  273. var PostInSamples = int.Parse(Post) * samplingFrequency;
  274. var eventOccuredAtSample = PreInSamples;
  275. newEvent.EventOccurredAtSample = eventOccuredAtSample;
  276. }
  277. else
  278. {
  279. var eventOccuredAtSample = (int)(numberofsamples / 2);
  280. newEvent.EventOccurredAtSample = eventOccuredAtSample; //Pretrigger and Postrigger are in seconds, the eventOccuredfAtSample is in number of samples
  281. }
  282.  
  283. //Set the acitivity level and symptoms to 0 since they're not supported in Sirona
  284. newEvent.PatientActivityLevel = 0;
  285. newEvent.PatientSymptom = 0;
  286.  
  287. //Set the AmplitudeMultiplier value in our DB which is the inverse of ADC gain for Sirona
  288. newEvent.AmplitudeMultiplier = 1 / gain;
  289.  
  290. var patient = context.Patients.FirstOrDefault(o => o.Id == study.PatientId);
  291. var baseTimeDetails = baseTime.Split(':');
  292. var baseDateDetails = baseDate.Split('/');
  293.  
  294. var UTCHoursPart = UTCValue.Hours;
  295. var UTCMinutesPart = UTCValue.Minutes;
  296. var UTCMinutes = UTCHoursPart * 60 + UTCMinutesPart;
  297.  
  298. //Adding the start time of the event in UTC, because in CloudBeat Database it's all in UTC
  299. var startTime = StripDate.AddMinutes(-UTCMinutes);
  300. newEvent.StartTime = startTime;
  301. newEvent.EndTime = startTime.AddSeconds(numberofsamples / samplingFrequency);
  302. newEvent.MinutesFromUTC = UTCMinutes;
  303. if (context.Events.Any(x => x.StudyId == studyId && x.Type == eventType && x.StartTime == startTime))
  304. {
  305. newEvent = context.Events.FirstOrDefault(x => x.StudyId == studyId && x.Type == eventType && x.StartTime == startTime);
  306.  
  307. }
  308. else
  309. {
  310.  
  311. context.Events.Add(newEvent);
  312. context.SaveChanges();
  313. }
  314.  
  315. //Save the annotations in a CSV format
  316. if (File.Exists(tempFolder + "/" + recordName + ".atr.tab"))
  317. {
  318. Utils.ConvertFromTabToCSV(tempFolder + "/" + recordName + ".atr.tab", tempFolder + "/" + newEvent.Id + "_ann.csv", 0, true);
  319. }
  320.  
  321. // convert the output ECG file from tab format to CSV format
  322. Utils.ConvertFromTabToCSV(tempFolder + "/" + recordName + ".dat.tab", tempFolder + "/" + newEvent.Id + ".csv", int.Parse(numberOfSignals), false);
  323.  
  324. if (newEvent.NumberOfECGFiles == 0)
  325. {
  326. var csvFile = File.ReadAllLines(tempFolder + "/" + newEvent.Id + ".csv");
  327. newEvent.NumberOfECGFiles = (int)(csvFile.Length / (60 * samplingFrequency));
  328.  
  329. }
  330.  
  331. if (newEvent.EventOccurredAtSample > newEvent.NumberOfECGFiles * 60 * samplingFrequency)
  332. {
  333. newEvent.EventOccurredAtSample = (newEvent.NumberOfECGFiles * 60 * samplingFrequency) / 2;
  334. }
  335.  
  336. //Make the eventOccurredAtSample related to the minute in the middle and not the first minute
  337. if (studyId < 150)
  338. {
  339. newEvent.EventOccurredAtSample = newEvent.EventOccurredAtSample - 60 * samplingFrequency;
  340. Utils.CreatePreviewChart(studyId, newEvent.Id, tempFolder, (int)newEvent.NumberOfECGFiles, (int)newEvent.EventOccurredAtSample + 60 * samplingFrequency, (double)newEvent.AmplitudeMultiplier, samplingFrequency);
  341.  
  342. }
  343. else
  344. {
  345. if (newEvent.EventOccurredAtSample < 0)
  346. {
  347. newEvent.EventOccurredAtSample = 0;
  348. }
  349.  
  350. //Create image for triage
  351. Utils.CreatePreviewChart(studyId, newEvent.Id, tempFolder, (int)newEvent.NumberOfECGFiles, (int)newEvent.EventOccurredAtSample, (double)newEvent.AmplitudeMultiplier, samplingFrequency);
  352. }
  353. //Create image for event control
  354. Utils.CreateOverviewChart(studyId, newEvent.Id, newEvent.StartTime.Value, (int)newEvent.NumberOfECGFiles, (int)newEvent.EventOccurredAtSample, samplingFrequency, (double)newEvent.AmplitudeMultiplier, tempFolder);
  355.  
  356.  
  357. //Upload ECG CSV, annotations CSV and images to the blob
  358. var outputBlob = study.Id + "/ecg";
  359. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + ".csv");
  360. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + ".csv");
  361.  
  362. if (File.Exists(tempFolder + "/" + recordName + ".atr.tab"))
  363. {
  364. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + "_ann.csv");
  365. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + "_ann.csv");
  366. }
  367.  
  368. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + ".gif");
  369. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + ".gif");
  370.  
  371. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + "-overview.gif");
  372. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + "-overview.gif");
  373.  
  374. //Label the event as ready
  375. newEvent.Ready = true;
  376. context.SaveChanges();
  377.  
  378. //////////////SAP TRANSMISSION API CALL///////////////////
  379.  
  380. var provider = context.Users.FirstOrDefault(o => o.Id == study.ProviderId);
  381.  
  382. if (device.CompanyId == 12)//TODO replace with actual company ID
  383. {
  384. var addressLine2Parts = (!string.IsNullOrEmpty(patient.AddressLine2)) ? Cipher.Decrypt(patient.AddressLine2, true).Split(',') : new string[0];
  385.  
  386. var orderCreate = new OrderCreate(); //Strongly Typed JSON Object
  387. var header = new Header
  388. {
  389. CreationTimeStamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"),//TIMESTAMP in UTC
  390. Identifier = "TRANS"//From JSON
  391. };
  392.  
  393. orderCreate.Header = header;
  394.  
  395. var medicalCenter = patient.MedicalCenter;
  396.  
  397. var orderLineItemLp = new OrderLineItemLp
  398. {
  399. MaterialNum = (!string.IsNullOrEmpty(device.Notes)) ? device.Notes : "", //TODO: Change it when agreed where to put it
  400. ItemSerialLp = new ItemSerialLp
  401. {
  402. Serial = device.SerialNumber,
  403. PickQty = "1",
  404. ItemUoM = "PC"
  405.  
  406. }
  407. };
  408.  
  409. var orderHeader = new OrderHeader
  410. {
  411. PhysicianName = provider.LastName + ", " + provider.LastName,
  412. PhyNPINumber = "",//NOT PRESENT
  413. PatientName = Cipher.Decrypt(patient.LastName, true) + ", " + Cipher.Decrypt(patient.LastName, true),//Patient Name
  414. EnrollmentID = study.Id.ToString(),
  415. ShipTo = new ShipTo
  416. {
  417. ShipToID = medicalCenter.Email,//SHIPTO = MEDICAL CENTER
  418. AdrFName = medicalCenter.Name
  419. },
  420. OrderLineItemLp = orderLineItemLp
  421.  
  422. };
  423.  
  424. orderCreate.OrderHeader = orderHeader;
  425.  
  426. RootObject rootObject = new RootObject
  427. {
  428. OrderCreate = orderCreate
  429. };
  430.  
  431. Functions.PingSAPForNewTransmission(rootObject);
  432. }
  433.  
  434. //////////////END SAP TRANSMISSION API CALL///////////////////
  435.  
  436. //Call the webservice to notify the users
  437. var parameters = "{'eventID':" + newEvent.Id + "}";
  438.  
  439. var httpClient = new HttpClient();
  440. var content = new StringContent(parameters, Encoding.UTF8, "application/json");
  441. var url = Utils.NotificationsURL + @"/User/Services/WebServices.asmx/SendNotifications";
  442.  
  443. httpClient.PostAsync(url, content).Wait();
  444. }
  445. else
  446. {
  447. //ToDo: Change the type, name and description
  448. if (File.Exists(tempFolder + "/" + recordName + ".atr"))
  449. {
  450. SByteParser.ParseSironaAnnotation(tempFolder + "/" + recordName + ".atr");
  451. }
  452. //Save the annotations in a CSV format
  453. if (File.Exists(tempFolder + "/" + recordName + ".atr.tab"))
  454. {
  455. Utils.ConvertFromTabToCSV(tempFolder + "/" + recordName + ".atr.tab", tempFolder + "/TheOriginal_ann.csv", 0, true);
  456. }
  457.  
  458. SByteParser.ParseSironaECG(tempFolder + "/" + recordName + ".dat", numberOfSignals);
  459. // convert the output ECG file from tab format to CSV format
  460. Utils.ConvertFromTabToCSV(tempFolder + "/" + recordName + ".dat.tab", tempFolder + "/TheOriginal.csv", int.Parse(numberOfSignals), false);
  461.  
  462. string[] TheOriginalDat = File.ReadAllLines(tempFolder + "/TheOriginal.csv");
  463. string[] TheOriginalAtr = File.ReadAllLines(tempFolder + "/TheOriginal_ann.csv");
  464.  
  465. int numberofsamples = samplingFrequency * int.Parse(StripLength);
  466. int NumberOfECGFiles = (int)Math.Ceiling((double)numberofsamples / (60 * samplingFrequency));
  467.  
  468. int samplesInOneMinute = 60 * samplingFrequency;
  469. //Array that will hold values of the current temporary part of the strip (1 minute)
  470. string[] TempDat = new string[samplesInOneMinute];
  471. string[] TempAtr = new string[TheOriginalAtr.Length];
  472.  
  473. int fromLine = 0;
  474. int toLine = 0;
  475.  
  476. for (int i = 0; i < NumberOfECGFiles; i++)
  477. {
  478. fromLine = toLine;
  479. toLine = 0;
  480. //To account for the last seconds after the before last minute
  481. int samplesToCopy = samplesInOneMinute;
  482. if( i == NumberOfECGFiles - 1)
  483. {
  484. samplesToCopy = TheOriginalDat.Length - samplesInOneMinute * i;
  485. }
  486. TempDat = new string[samplesToCopy];
  487.  
  488. Array.Copy(TheOriginalDat, i * samplesInOneMinute, TempDat, 0, samplesToCopy);
  489.  
  490. TempAtr = new string[TheOriginalAtr.Length];
  491. try
  492. {
  493. foreach (var line in TheOriginalAtr)
  494. {
  495. string[] columns = line.Split(',');
  496. int CurrentMinute = (int)(int.Parse(columns[0]) / (60 * samplingFrequency));
  497. if (CurrentMinute > i)
  498. {
  499. break;
  500. }
  501. toLine++;
  502. }
  503.  
  504. Array.Copy(TheOriginalAtr, fromLine, TempAtr, 0, (toLine - fromLine));
  505. TempAtr = TempAtr.Where(o => o != "").ToArray();
  506. TempAtr = TempAtr.Where(o => o != null).ToArray();
  507. }
  508. catch (Exception ex)
  509. {
  510. AtrCorrupted = true;
  511.  
  512. string exceptionMessage = ex.Message;
  513.  
  514. var errorFile = studiesContainer.GetAppendBlobReference(studyId + "/error.csv");
  515.  
  516. if (!errorFile.Exists())
  517. {
  518. errorFile.CreateOrReplace();
  519. }
  520. errorFile.Properties.CacheControl = "no-cache";
  521. errorFile.SetProperties();
  522. using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(message + ":" + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine)))
  523. {
  524. errorFile.AppendBlock(ms);
  525. }
  526.  
  527. }
  528. var newEvent = new Event();
  529. newEvent.StudyId = study.Id;
  530.  
  531. newEvent.Name = eventType;
  532. newEvent.Type = eventType;
  533. if (i == 0)
  534. {
  535. newEvent.Description = "DDR Start";
  536. }
  537. else if(i == NumberOfECGFiles - 1)
  538. {
  539. newEvent.Description = "DDR End";
  540. }
  541. else
  542. {
  543. newEvent.Description = "DDR Cont.";
  544. }
  545. //Set the acitivity level and symptoms to 0 since they're not supported in Sirona
  546. newEvent.PatientActivityLevel = 0;
  547. newEvent.PatientSymptom = 0;
  548.  
  549. //Set the AmplitudeMultiplier value in our DB which is the inverse of ADC gain for Sirona
  550. newEvent.AmplitudeMultiplier = 1 / gain;
  551.  
  552. var UTCHoursPart = UTCValue.Hours;
  553. var UTCMinutesPart = UTCValue.Minutes;
  554. var UTCMinutes = UTCHoursPart * 60 + UTCMinutesPart;
  555. //Adding the start time of the event in UTC, because in CloudBeat Database it's all in UTC
  556. var startTime = StripDate.AddMinutes(-UTCMinutes);
  557.  
  558. newEvent.StartTime = startTime.AddSeconds((i * samplesInOneMinute)/samplingFrequency);
  559. newEvent.EndTime = startTime.AddSeconds((i * samplesInOneMinute + samplesToCopy)/samplingFrequency);
  560. newEvent.EventOccurredAtSample = samplesToCopy / 2;
  561. newEvent.MinutesFromUTC = UTCMinutes;
  562. if (context.Events.Any(x => x.StudyId == studyId && x.Type == eventType && x.StartTime == newEvent.StartTime && x.Description == newEvent.Description))
  563. {
  564. newEvent = context.Events.FirstOrDefault(x => x.StudyId == studyId && x.Type == eventType && x.StartTime == newEvent.StartTime && x.Description == newEvent.Description);
  565.  
  566. }
  567. else
  568. {
  569.  
  570. context.Events.Add(newEvent);
  571. context.SaveChanges();
  572. }
  573.  
  574. File.WriteAllLines(tempFolder + "/" + newEvent.Id + ".csv", TempDat);
  575. if (!AtrCorrupted)
  576. {
  577. File.WriteAllLines(tempFolder + "/" + newEvent.Id + "_ann.csv", TempAtr);
  578. }
  579. //Create image for triage
  580. Utils.CreatePreviewChart(studyId, newEvent.Id, tempFolder, 1, (int)(samplesToCopy/2), (double)newEvent.AmplitudeMultiplier, samplingFrequency);
  581.  
  582. //Create image for event control
  583. Utils.CreateOverviewChart(studyId, newEvent.Id, newEvent.StartTime.Value, 1, (int)(samplesToCopy / 2), samplingFrequency, (double)newEvent.AmplitudeMultiplier, tempFolder);
  584.  
  585. //Upload ECG CSV, annotations CSV and images to the blob
  586. var outputBlob = study.Id + "/ecg";
  587. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + ".csv");
  588. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + ".csv");
  589. if (!AtrCorrupted)
  590. {
  591. if (File.Exists(tempFolder + "/" + recordName + ".atr.tab"))
  592. {
  593. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + "_ann.csv");
  594. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + "_ann.csv");
  595. }
  596. }
  597.  
  598. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + ".gif");
  599. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + ".gif");
  600.  
  601. blob = studiesContainer.GetBlockBlobReference(outputBlob + @"/" + newEvent.Id + "-overview.gif");
  602. blob.UploadFromFile(tempFolder + "/" + newEvent.Id + "-overview.gif");
  603.  
  604. //Label the event as ready
  605. newEvent.Ready = true;
  606. context.SaveChanges();
  607. }
  608. }
  609. }
  610. }
  611. }
  612.  
  613. //using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, ("After Try: " + message)) + Environment.NewLine)))
  614. //{
  615. // await tryingBlob.AppendBlockAsync(ms);
  616.  
  617. //}
  618. #endregion
  619. }
  620. catch (Exception ex)
  621. {
  622. string exceptionMessage = ex.Message;
  623.  
  624. var errorFile = studiesContainer.GetAppendBlobReference(studyId + "/error.csv");
  625.  
  626. if (!errorFile.Exists())
  627. {
  628. errorFile.CreateOrReplace();
  629. }
  630. errorFile.Properties.CacheControl = "no-cache";
  631. errorFile.SetProperties();
  632. using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(message + ":" + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine)))
  633. {
  634. errorFile.AppendBlock(ms);
  635. }
  636.  
  637.  
  638. return;
  639. }
  640.  
  641. //Delete the temp file created by this instance
  642. Utils.DeleteDirectory(tempFolder);
  643.  
  644. }
  645.  
  646. unsafe static public Boolean ParseSironaECG(string filePath, string numberOfSignals)
  647. {
  648. try
  649. {
  650. string myString = "";
  651. for (int i = 0; i < 255; i++) myString += " ";
  652.  
  653. //get the byte array
  654. byte[] bytes = Encoding.ASCII.GetBytes(filePath);
  655. byte[] errbytes = Encoding.ASCII.GetBytes(myString);
  656.  
  657. sbyte* sbFileName;
  658. sbyte* sbError;
  659.  
  660.  
  661. fixed (byte* ptr_bytes = &bytes[0])
  662. sbFileName = (sbyte*)ptr_bytes;
  663. fixed (byte* ptr_errbytes = &errbytes[0])
  664. sbError = (sbyte*)ptr_errbytes;
  665. // PhysionetParser.PhysionetParser.readSironaEcg(sbFileName);
  666. PhysionetParser.PhysionetParser.readSironaEcg(sbFileName, int.Parse(numberOfSignals));
  667.  
  668.  
  669. //Upload the parsed file to the blob
  670. var context = new StorageContext();
  671.  
  672.  
  673. return true;
  674. }
  675. catch (Exception ex)
  676. {
  677. return false;
  678. }
  679.  
  680. }
  681.  
  682.  
  683.  
  684.  
  685.  
  686. }
  687. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement