/// <summary> /// Save the calibration values /// </summary> private bool SaveCalibrationValues(bool spreadLastMeasure) { try { // Save the calibration in database this.UserSettingsRepository.UpdateSensorCalibration(this.CurrentUserSettings, this.CalibrationSourceValue, this.CalibrationRevisedValue); this.CurrentUserSettings = this.UserSettingsRepository.GetCurrentUserSettings(); // Get the last measure GlucoseMeasure lastMeasure = this.GlucoseMeasureRepository.GetLastMeasureByUser(this.CurrentUser.Id); if (lastMeasure != null) { Log.Debug("BluetoothPageViewModel", $"SaveCalibrationValues : lastMeasure=[{lastMeasure.GlucoseLevelMGDL}], Offset=[{this.CurrentUserSettings.MeasureOffset}]"); // Update the last measure offset this.GlucoseMeasureRepository.UpdateMeasureOffset(lastMeasure, this.CurrentUserSettings.MeasureOffset, this.settings); // Spread the value if (spreadLastMeasure) { GlucoseMeasure updated = this.GlucoseMeasureRepository.GetLastMeasureByUser(this.CurrentUser.Id); this.eventAggregator.GetEvent <LastMeasureReceivedEvent>().Publish(this.CalibrationRevisedValue); } } return(true); } catch (Exception e) { return(false); } }
/// <summary> /// Creates a GlucoseMeasure /// </summary> /// <param name="entity">The measure to create</param> public void Create(GlucoseMeasure entity, string userId) { this.realm.Write(() => { entity.UserId = userId; this.realm.Add(entity); }); }
/// <summary> /// Update the userId measure for a glucose measure /// </summary> /// <param name="measure"></param> /// <param name="isInTheMedicalZone"></param> public void ChangeIsInTheMedicalZone(GlucoseMeasure measure, bool isInTheMedicalZone) { using (var trans = realm.BeginWrite()) { measure.InTheMedicalZone = isInTheMedicalZone; trans.Commit(); } }
/// <summary> /// Update the userId measure for a glucose measure /// </summary> /// <param name="measure"></param> /// <param name="userId"></param> public void ChangeUserId(GlucoseMeasure measure, string userId) { using (var trans = realm.BeginWrite()) { measure.UserId = userId; trans.Commit(); } }
/// <summary> /// Update the measure offset for a GlucoseMeasure /// </summary> /// <param name="measure">The measure to update</param> /// <param name="offsetValue">The offset value coming from the calibration</param> /// <param name="appSettings">The appSettings</param> public GlucoseMeasure UpdateMeasureOffset(GlucoseMeasure measure, float calibrationOffset, AppSettings appSettings) { using (var trans = realm.BeginWrite()) { measure.CalibrationOffset = calibrationOffset; measure.GlucoseLevelMGDL = (float)Math.Round((decimal)measure.GlucoseLevelRaw / 10) + calibrationOffset; measure.GlucoseLevelMMOL = (float)FreeStyleLibreUtils.ConvertMGDLToMMolPerLiter(appSettings, measure.GlucoseLevelMGDL); trans.Commit(); } return(measure); }
/// <summary> /// This method processes the sensor data /// </summary> /// <param name="readingSession">The reading session</param> public void ProcessSensorData(MeasureReadingSession readingSession) { if (readingSession == null) { Log.Debug(LOG_TAG, GetType() + ".ProcessSensorData: readingSession is NULL"); return; } Sensor currentSensor; User currentUser = this.userRepository.GetCurrentUser(); this.userRepository.ChangeName(currentUser, "Josoa"); currentUser = this.userRepository.GetCurrentUser(); // if the sensor extracted from the reading session is New if (!this.sensorRepository.Exists(readingSession.SensorId)) { Log.Debug(LOG_TAG, GetType() + ".ProcessSensorData: register new sensor. readingSession.SensorId=[" + readingSession.SensorId + "]"); // first, find the current sensor currentSensor = this.sensorRepository.GetCurrentSensor(); // if the sensor exits, we "remove" it if (currentSensor != null) { Log.Debug(LOG_TAG, GetType() + ".ProcessSensorData: removing sensor=[" + currentSensor.Id + "]"); this.sensorRepository.Remove(currentSensor); } // then, we register the new sensor Sensor toRegister = new Sensor(); toRegister.Id = readingSession.SensorId; this.sensorRepository.RegisterNewSensor(toRegister); currentSensor = this.sensorRepository.GetCurrentSensor(); } else { currentSensor = this.sensorRepository.GetCurrentSensor(); Log.Debug(LOG_TAG, GetType() + ".ProcessSensorData: updating existing sensor=[" + currentSensor.Id + "]"); } GlucoseMeasure lastGlucoseMeasure = readingSession.CurrentMeasure; //Update the device battery level this.userRepository.UpdateDeviceBatteryPercentage(currentUser, readingSession.BatteryLevel); //Update the last value checked time this.userRepository.UpdateLastValueTimeStamp(currentUser, lastGlucoseMeasure.RealDateTimeOffset); //Send notification to update battery and data in drive page this.eventAggregator.GetEvent <DrivePageDataUpdateEvent>().Publish(); }
/// <summary> /// This method process the FullData. Once the last byte is received, we process the consolidated array. /// </summary> private void ProcessData() { //WeakHashMap don't need the Tomato Header part byte[] data = Arrays.CopyOfRange(this.FullData, TOMATO_HEADER_LENGTH, TOMATO_HEADER_LENGTH + 344); // MIAOMIAO PROTOCOL : The 4th byte is where the sensor status is. // TODO : Quoi faire ici ? On abandonne la lecture ? Noon ... --> no one no oneeeeeee ne sait if (!FreeStyleLibreUtils.IsSensorReady(data[4])) { Log.Debug(LOG_TAG, "MiaoMiaoProtocol.ProcessData: Sensor is not ready, we should Ignoring reading!"); } // Here we are !! The show is about to begin :D // MIAOMIAO Protocol long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); ReadingSession.LastReadingTimestamp = now; // MIAOMIAO Protocol. Trend index is at the 26th index int indexTrend = data[26] & 0xFF; // MIAOMIAO Protocol. History index is at the 27th index int indexHistory = data[27] & 0xFF; // MIAOMIAO Protocol. SensorTime is at 317th and 316th index int sensorTime = 256 * (data[317] & 0xFF) + (data[316] & 0xFF); long sensorStartTime = now - sensorTime * this.settings.MILLISECONDS_IN_MINUTE; Log.Debug(LOG_TAG, "MiaoMiaoProtocol.ProcessFullData: sensorTime=[" + sensorTime + "]"); // option to use 13 bit mask bool thirteen_bit_mask = true; // loads history values (ring buffer, starting at index_trent. byte 124-315) for (int index = 0; index < 32; index++) { int i = indexHistory - index - 1; if (i < 0) { i += 32; } GlucoseMeasure measure = new GlucoseMeasure { GlucoseLevelRaw = FreeStyleLibreUtils.ExtractGlucoseRaw(new byte[] { data[(i * 6 + 125)], data[(i * 6 + 124)] }, thirteen_bit_mask), }; // we don't need null values if (measure.GlucoseLevelRaw == 0) { continue; } int time = Math.Max(0, Math.Abs((sensorTime - 3) / 15) * 15 - index * 15); measure.Timestamp = sensorStartTime + time * this.settings.MILLISECONDS_IN_MINUTE; measure.RealDateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(sensorStartTime + time * this.settings.MILLISECONDS_IN_MINUTE); measure.SensorTime = time; measure.GlucoseLevelMGDL = (float)Math.Round((decimal)measure.GlucoseLevelRaw / 10); measure.GlucoseLevelMMOL = (float)FreeStyleLibreUtils.ConvertMGDLToMMolPerLiter(this.settings, Math.Round((double)measure.GlucoseLevelRaw / 10)); ReadingSession.PushHistoryMeasure(measure); } // loads trend values (ring buffer, starting at index_trent. byte 28-123) for (int index = 0; index < 16; index++) { int i = indexTrend - index - 1; if (i < 0) { i += 16; } GlucoseMeasure measure = new GlucoseMeasure { GlucoseLevelRaw = FreeStyleLibreUtils.ExtractGlucoseRaw(new byte[] { data[(i * 6 + 29)], data[(i * 6 + 28)] }, thirteen_bit_mask) }; // we don't need null values if (measure.GlucoseLevelRaw == 0) { continue; } int time = Math.Max(0, sensorTime - index); measure.RealDateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(sensorStartTime + time * this.settings.MILLISECONDS_IN_MINUTE); measure.Timestamp = sensorStartTime + time * this.settings.MILLISECONDS_IN_MINUTE; measure.SensorTime = time; measure.GlucoseLevelMGDL = (float)Math.Round((decimal)measure.GlucoseLevelRaw / 10); measure.GlucoseLevelMMOL = (float)FreeStyleLibreUtils.ConvertMGDLToMMolPerLiter(this.settings, Math.Round((double)measure.GlucoseLevelRaw / 10)); ReadingSession.PushTrendMeasure(measure); Log.Debug(LOG_TAG, $"MiaoMiaoProtocol.ProcessData: measure=[{measure.ToString()}"); } // The current measure if (ReadingSession.TrendMeasures.Count > 0) { ReadingSession.CurrentMeasure = ReadingSession.TrendMeasures[0]; } ReadingSession.CalculateSmothedData5Points(); // At the end, we end the ReadingMesureSession ReadingSession.End(); // send the event to notify that the reading is over this.EventAggregator.GetEvent <EndReadingEvent>().Publish(""); // Notify the GlucoseService that it's done this.GlucoseService.HandleReadingSession(ReadingSession); }
/// <summary> /// This method determines if a measure is in the medical zone /// </summary> /// <param name="measure">The measure to check</param> /// <returns>True if the measure is in the medical zone. False in other case</returns> private bool InTheMedicalZone(GlucoseMeasure measure) { // The medical zone is fixed (verified MGDL) return(this.appSettings.MEDICAL_ZONE_MGDL_MIN <= measure.GlucoseLevelMGDL && measure.GlucoseLevelMGDL <= this.appSettings.MEDICAL_ZONE_MGDL_MAX); }
/// <summary> /// Spreads the last measure on the application (database, UI, alerts) /// </summary> /// <param name="lastMeasure"></param> private void SpreadLastMeasure(float lastMeasure) { var currentUser = this.userRepository.GetCurrentUser(); var userSettings = this.userSettingsRepository.GetCurrentUserSettings(); long countExistingMesures = this.glucoseMeasureRepository.CountByUser(currentUser.Id); bool isFirstReading = countExistingMesures == 0; // 1 - Driving mode // NOTE : We only handle MGDL Measure for the H&D MVP this.userRepository.ChangeCurrentMeasure(currentUser, lastMeasure); // 2 The notification channel var notification = new NotificationMeasure(); notification.NotificationMessage = string.Format(Utils.GetTranslation("NotificationMessageCurrentMeasure"), HiLowValueHelper.NewMeasureToString(lastMeasure)); notification.NewMeasure = lastMeasure; notification.MinimumGlucoseTreshold = userSettings.MinimumGlucoseTreshold; notification.MaximumGlucoseTreshold = userSettings.MaximumGlucoseTreshold; notification.IsAlert = userRepository.GetCurrentUser().IsAlert; //Current Trend management // GlucoseMeasure pastFifteenMinMeasure = glucoseMeasureRepository.GetPastFifteenMinutesMeasureByUser(currentUser.Id); float? pastFifteenMinMeasureValue = null; if (pastFifteenMinMeasure != null) { pastFifteenMinMeasureValue = pastFifteenMinMeasure.GlucoseLevelMGDL; } //Trend management : Builder // switch (TrendHelper.ValuesToTypeTrend(lastMeasure, pastFifteenMinMeasureValue)) { case MeasureTrend.IncreasingHeavy: notification.MeasureTrend = MeasureTrend.IncreasingHeavy; break; case MeasureTrend.Increasing: notification.MeasureTrend = MeasureTrend.Increasing; break; case MeasureTrend.Constant: notification.MeasureTrend = MeasureTrend.Constant; break; case MeasureTrend.Decreasing: notification.MeasureTrend = MeasureTrend.Decreasing; break; case MeasureTrend.DecreasingHeavy: notification.MeasureTrend = MeasureTrend.DecreasingHeavy; break; default: notification.MeasureTrend = MeasureTrend.None; break; } //Trend management : Notifications // //Save the measure trend in the user data this.userRepository.UpdateMeasureTrend(currentUser, notification.MeasureTrend); //Send the measure trend event to the drive page this.eventAggregator.GetEvent <TrendEvent>().Publish(notification.MeasureTrend); //Send the measure trend event to the notification this.eventAggregator.GetEvent <NotificationMeasureEvent>().Publish(notification); // 3 - Alerts raised to the user ? if (userRepository.GetCurrentUser().IsAlert) { if (lastMeasure > userSettings.MaximumGlucoseTreshold || lastMeasure < userSettings.MinimumGlucoseTreshold) { notification.NotificationMessage = string.Format(Utils.GetTranslation("NotificationMessageAlertGlycemia"), HiLowValueHelper.NewMeasureToString(lastMeasure)); this.eventAggregator.GetEvent <PushNotificationAlertEvent>().Publish(notification); } } this.precedingMeasure = lastMeasure; }
/// <summary> /// This method processes the glucose measures /// </summary> /// <param name="userId">The userId</param> /// <param name="freshMeasures">The list of the fresh measures</param> public void ProcessMeasuresData(string userId, MeasureReadingSession readingSession) { var currentUser = this.userRepository.GetCurrentUser(); var userSettings = this.userSettingsRepository.GetCurrentUserSettings(); bool isCreation = false; // first, we check the age of the sensor var currentSensor = this.sensorRepository.GetCurrentSensor(); long newSensorAge = readingSession.TrendMeasures[readingSession.TrendMeasures.Count - 1].SensorTime; long savedSensorAge = currentSensor.Age; if (newSensorAge > savedSensorAge) { Log.Debug(LOG_TAG, GetType() + ".ProcessMeasuresData: Sensor age has advanced. Try to insert measures" + savedSensorAge); savedSensorAge = newSensorAge; this.sensorRepository.UpdateSensorAge(currentSensor, savedSensorAge); } else if (newSensorAge == savedSensorAge) { Log.Debug(LOG_TAG, GetType() + ".ProcessMeasuresData: Sensor age has not advanced. sensorAge=[" + savedSensorAge + "]"); return; // do not try to insert again } else { Log.Debug(LOG_TAG, GetType() + ".ProcessMeasuresData: Sensor age has gone backwards!!! " + savedSensorAge); savedSensorAge = newSensorAge; this.sensorRepository.UpdateSensorAge(currentSensor, savedSensorAge); } GlucoseMeasure lastInsertedMeasure = this.glucoseMeasureRepository.GetLastMeasureByUser(userId); // create each GlucoseMeasure foreach (GlucoseMeasure measure in readingSession.GetAllMeasures()) { if (lastInsertedMeasure != null && lastInsertedMeasure.Timestamp > measure.Timestamp) { continue; } // possibly, the trend measures interval could be one minute // we only want 5 minutes interval if (measure.SensorTime % appSettings.MEASURE_NOTIFICATION_INTERVAL != 0) { continue; } isCreation = true; // creation first measure.Id = Guid.NewGuid().ToString(); this.glucoseMeasureRepository.Create(measure, userId); // then updates // measureoffset this.glucoseMeasureRepository.UpdateMeasureOffset(measure, userSettings.MeasureOffset, appSettings); // In The medical zone //medical zone this.glucoseMeasureRepository.ChangeIsInTheMedicalZone(measure, InTheMedicalZone(measure)); Log.Debug(LOG_TAG, GetType() + ".ProcessMeasuresData: Creating measure " + measure.ToString()); } GlucoseMeasure lastGlucoseMeasure = readingSession.CurrentMeasure; //Last glucose measure additionnal setup if (lastGlucoseMeasure.Id == null) { //Add to the last glucose measure an generatedId lastGlucoseMeasure.Id = Guid.NewGuid().ToString(); //Save the last glucose measure into the database this.glucoseMeasureRepository.Create(lastGlucoseMeasure, userId); } if (lastGlucoseMeasure.UserId == null) { //Add to the last glucose measure an userId this.glucoseMeasureRepository.ChangeUserId(lastGlucoseMeasure, userId); } //Check if the measure is in the medical zone this.glucoseMeasureRepository.ChangeIsInTheMedicalZone(lastGlucoseMeasure, InTheMedicalZone(lastGlucoseMeasure)); //Apply the offset lastGlucoseMeasure = this.glucoseMeasureRepository.UpdateMeasureOffset(lastGlucoseMeasure, userSettings.MeasureOffset, appSettings); Log.Debug(LOG_TAG, GetType() + ".ProcessMeasuresData: lastMeasure = " + lastGlucoseMeasure.ToString()); var toPublish = this.appSettings.HANDLE_MGDL_MEASURE ? lastGlucoseMeasure.GlucoseLevelMGDL : lastGlucoseMeasure.GlucoseLevelMMOL; // Spread the current last glucose measure this.eventAggregator.GetEvent <LastMeasureReceivedEvent>().Publish(toPublish); }
/// <summary> /// Push a GlucoseMeasure in the trend list /// </summary> /// <param name="measure">The measure to push</param> public void PushTrendMeasure(GlucoseMeasure measure) { this.TrendMeasures.Add(measure); }
/// <summary> /// Push a GlucoseMeasure in the history list /// </summary> /// <param name="measure">The measure to push</param> public void PushHistoryMeasure(GlucoseMeasure measure) { this.HistoryMeasures.Add(measure); }