Skip to content

Commit cbf0590

Browse files
authored
Merge pull request #586 from tidepool-org/ps2/LOOP-4696/algorithm-test
LOOP-4696 Algorithm test updates
2 parents 686f7a5 + 6b250a0 commit cbf0590

12 files changed

+2276
-71
lines changed

Loop.xcodeproj/project.pbxproj

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@
411411
C11BD0552523CFED00236B08 /* SimpleBolusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C11BD0542523CFED00236B08 /* SimpleBolusViewModel.swift */; };
412412
C1201E2C23ECDBD0002DA84A /* WatchContextRequestUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1201E2B23ECDBD0002DA84A /* WatchContextRequestUserInfo.swift */; };
413413
C1201E2D23ECDF3D002DA84A /* WatchContextRequestUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1201E2B23ECDBD0002DA84A /* WatchContextRequestUserInfo.swift */; };
414+
C13072BA2A76AF31009A7C58 /* live_capture_predicted_glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = C13072B92A76AF31009A7C58 /* live_capture_predicted_glucose.json */; };
415+
C13072BE2A76AF97009A7C58 /* live_capture_doses.json in Resources */ = {isa = PBXBuildFile; fileRef = C13072BD2A76AF97009A7C58 /* live_capture_doses.json */; };
416+
C13072C02A76B041009A7C58 /* live_capture_carb_entries.json in Resources */ = {isa = PBXBuildFile; fileRef = C13072BF2A76B041009A7C58 /* live_capture_carb_entries.json */; };
417+
C13072C42A76B0B1009A7C58 /* live_capture_historic_glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = C13072C32A76B0B1009A7C58 /* live_capture_historic_glucose.json */; };
414418
C13255D6223E7BE2008AF50C /* BolusProgressTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C1F8B1DB223862D500DD66CF /* BolusProgressTableViewCell.xib */; };
415419
C13DA2B024F6C7690098BB29 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13DA2AF24F6C7690098BB29 /* UIViewController.swift */; };
416420
C148CEE724FD91BD00711B3B /* DeliveryUncertaintyAlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C148CEE624FD91BD00711B3B /* DeliveryUncertaintyAlertManager.swift */; };
@@ -1412,6 +1416,10 @@
14121416
C12CB9B423106A6100F84978 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Intents.strings; sourceTree = "<group>"; };
14131417
C12CB9B623106A6200F84978 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Intents.strings; sourceTree = "<group>"; };
14141418
C12CB9B823106A6300F84978 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Intents.strings; sourceTree = "<group>"; };
1419+
C13072B92A76AF31009A7C58 /* live_capture_predicted_glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = live_capture_predicted_glucose.json; sourceTree = "<group>"; };
1420+
C13072BD2A76AF97009A7C58 /* live_capture_doses.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = live_capture_doses.json; sourceTree = "<group>"; };
1421+
C13072BF2A76B041009A7C58 /* live_capture_carb_entries.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = live_capture_carb_entries.json; sourceTree = "<group>"; };
1422+
C13072C32A76B0B1009A7C58 /* live_capture_historic_glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = live_capture_historic_glucose.json; sourceTree = "<group>"; };
14151423
C13DA2AF24F6C7690098BB29 /* UIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = "<group>"; };
14161424
C148CEE624FD91BD00711B3B /* DeliveryUncertaintyAlertManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryUncertaintyAlertManager.swift; sourceTree = "<group>"; };
14171425
C14952142995822A0095AA84 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -1841,7 +1849,6 @@
18411849
isa = PBXGroup;
18421850
children = (
18431851
1DA7A84024476E98008257F0 /* Alerts */,
1844-
E950CA9429002E4B00B5B692 /* LoopDataManager */,
18451852
C16575722538AFF6004AE16E /* CGMStalenessMonitorTests.swift */,
18461853
A91E4C2224F86F1000BE9213 /* CriticalEventLogExportManagerTests.swift */,
18471854
C16B983F26B4898800256B05 /* DoseEnactorTests.swift */,
@@ -2738,6 +2745,17 @@
27382745
path = LoopCore;
27392746
sourceTree = "<group>";
27402747
};
2748+
C13072B82A76AF0A009A7C58 /* live_capture */ = {
2749+
isa = PBXGroup;
2750+
children = (
2751+
C13072B92A76AF31009A7C58 /* live_capture_predicted_glucose.json */,
2752+
C13072BD2A76AF97009A7C58 /* live_capture_doses.json */,
2753+
C13072BF2A76B041009A7C58 /* live_capture_carb_entries.json */,
2754+
C13072C32A76B0B1009A7C58 /* live_capture_historic_glucose.json */,
2755+
);
2756+
path = live_capture;
2757+
sourceTree = "<group>";
2758+
};
27412759
C16DA84022E8E104008624C2 /* Plugins */ = {
27422760
isa = PBXGroup;
27432761
children = (
@@ -2844,13 +2862,6 @@
28442862
path = high_and_stable;
28452863
sourceTree = "<group>";
28462864
};
2847-
E950CA9429002E4B00B5B692 /* LoopDataManager */ = {
2848-
isa = PBXGroup;
2849-
children = (
2850-
);
2851-
path = LoopDataManager;
2852-
sourceTree = "<group>";
2853-
};
28542865
E95D37FF24EADE68005E2F50 /* Store Protocols */ = {
28552866
isa = PBXGroup;
28562867
children = (
@@ -2901,6 +2912,7 @@
29012912
E9C58A7624DB510500487A17 /* Fixtures */ = {
29022913
isa = PBXGroup;
29032914
children = (
2915+
C13072B82A76AF0A009A7C58 /* live_capture */,
29042916
E9B355312937068A0076AB04 /* meal_detection */,
29052917
E90909EC24E35B3400F963D2 /* high_and_falling */,
29062918
E90909E124E352C300F963D2 /* low_with_low_treatment */,
@@ -3390,7 +3402,9 @@
33903402
buildActionMask = 2147483647;
33913403
files = (
33923404
E93E86CE24E2E02200FF40C8 /* high_and_stable_momentum_effect.json in Resources */,
3405+
C13072BA2A76AF31009A7C58 /* live_capture_predicted_glucose.json in Resources */,
33933406
E93E865424DB6CBA00FF40C8 /* retrospective_output.json in Resources */,
3407+
C13072BE2A76AF97009A7C58 /* live_capture_doses.json in Resources */,
33943408
E9C58A7F24DB529A00487A17 /* counteraction_effect_falling_glucose.json in Resources */,
33953409
E93E865624DB731900FF40C8 /* predicted_glucose_without_retrospective.json in Resources */,
33963410
E9B3553D293706CB0076AB04 /* long_interval_counteraction_effect.json in Resources */,
@@ -3403,6 +3417,7 @@
34033417
E90909D224E34AC500F963D2 /* high_and_rising_with_cob_insulin_effect.json in Resources */,
34043418
E90909F224E35B4D00F963D2 /* high_and_falling_counteraction_effect.json in Resources */,
34053419
E90909EE24E35B4000F963D2 /* high_and_falling_predicted_glucose.json in Resources */,
3420+
C13072C02A76B041009A7C58 /* live_capture_carb_entries.json in Resources */,
34063421
E90909DD24E34F1600F963D2 /* low_and_falling_carb_effect.json in Resources */,
34073422
E90909E924E3530200F963D2 /* low_with_low_treatment_predicted_glucose.json in Resources */,
34083423
E90909D124E34AC500F963D2 /* high_and_rising_with_cob_momentum_effect.json in Resources */,
@@ -3428,6 +3443,7 @@
34283443
E93E86C324E1FE6100FF40C8 /* flat_and_stable_counteraction_effect.json in Resources */,
34293444
E9C58A7E24DB529A00487A17 /* dynamic_glucose_effect_partially_observed.json in Resources */,
34303445
E90909F324E35B4D00F963D2 /* high_and_falling_carb_effect.json in Resources */,
3446+
C13072C42A76B0B1009A7C58 /* live_capture_historic_glucose.json in Resources */,
34313447
E93E86CA24E2E02200FF40C8 /* high_and_stable_insulin_effect.json in Resources */,
34323448
E93E86BB24E1FDC400FF40C8 /* flat_and_stable_momentum_effect.json in Resources */,
34333449
E93E86CB24E2E02200FF40C8 /* high_and_stable_carb_effect.json in Resources */,

Loop/Managers/DeviceDataManager.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ final class DeviceDataManager {
4545

4646
@Published var pumpIsAllowingAutomation: Bool
4747

48+
private var lastCGMLoopTrigger: Date = .distantPast
49+
4850
private let automaticDosingStatus: AutomaticDosingStatus
4951

5052
var closedLoopDisallowedLocalizedDescription: String? {
@@ -557,7 +559,6 @@ final class DeviceDataManager {
557559
private func processCGMReadingResult(_ manager: CGMManager, readingResult: CGMReadingResult, completion: @escaping () -> Void) {
558560
switch readingResult {
559561
case .newData(let values):
560-
log.default("CGMManager:%{public}@ did update with %d values", String(describing: type(of: manager)), values.count)
561562
loopManager.addGlucoseSamples(values) { result in
562563
if !values.isEmpty {
563564
DispatchQueue.main.async {
@@ -570,10 +571,8 @@ final class DeviceDataManager {
570571
loopManager.receivedUnreliableCGMReading()
571572
completion()
572573
case .noData:
573-
log.default("CGMManager:%{public}@ did update with no data", String(describing: type(of: manager)))
574574
completion()
575575
case .error(let error):
576-
log.default("CGMManager:%{public}@ did update with error: %{public}@", String(describing: type(of: manager)), String(describing: error))
577576
self.setLastError(error: error)
578577
completion()
579578
}
@@ -924,8 +923,14 @@ extension DeviceDataManager: CGMManagerDelegate {
924923

925924
func cgmManager(_ manager: CGMManager, hasNew readingResult: CGMReadingResult) {
926925
dispatchPrecondition(condition: .onQueue(queue))
926+
log.default("CGMManager:%{public}@ did update with %{public}@", String(describing: type(of: manager)), String(describing: readingResult))
927927
processCGMReadingResult(manager, readingResult: readingResult) {
928-
self.checkPumpDataAndLoop()
928+
let now = Date()
929+
if case .newData = readingResult, now.timeIntervalSince(self.lastCGMLoopTrigger) > .minutes(4.2) {
930+
self.log.default("Triggering loop from new CGM data at %{public}@", String(describing: now))
931+
self.lastCGMLoopTrigger = now
932+
self.checkPumpDataAndLoop()
933+
}
929934
}
930935
}
931936

@@ -1012,7 +1017,8 @@ extension DeviceDataManager: PumpManagerDelegate {
10121017

10131018
self.queue.async {
10141019
self.processCGMReadingResult(cgmManager, readingResult: result) {
1015-
if self.loopManager.lastLoopCompleted == nil || self.loopManager.lastLoopCompleted!.timeIntervalSinceNow < -.minutes(6) {
1020+
if self.loopManager.lastLoopCompleted == nil || self.loopManager.lastLoopCompleted!.timeIntervalSinceNow < -.minutes(4.2) {
1021+
self.log.default("Triggering Loop from refreshCGM()")
10161022
self.checkPumpDataAndLoop()
10171023
}
10181024
completion?()

Loop/Managers/LoopDataManager.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ final class LoopDataManager {
2727
case loopFinished
2828
}
2929

30+
let loopLock = UnfairLock()
31+
3032
static let LoopUpdateContextKey = "com.loudnate.Loop.LoopDataManager.LoopUpdateContext"
3133

3234
private let carbStore: CarbStoreProtocol
@@ -840,7 +842,23 @@ extension LoopDataManager {
840842
///
841843
/// Executes an analysis of the current data, and recommends an adjustment to the current
842844
/// temporary basal rate.
845+
///
843846
func loop() {
847+
848+
if let lastLoopCompleted, Date().timeIntervalSince(lastLoopCompleted) < .minutes(2) {
849+
print("Looping too fast!")
850+
}
851+
852+
let available = loopLock.withLockIfAvailable {
853+
loopInternal()
854+
return true
855+
}
856+
if available == nil {
857+
print("Loop attempted while already looping!")
858+
}
859+
}
860+
861+
func loopInternal() {
844862

845863
dataAccessQueue.async {
846864

@@ -1347,14 +1365,15 @@ extension LoopDataManager {
13471365
let retrospectiveStart = glucose.date.addingTimeInterval(-type(of: retrospectiveCorrection).retrospectionInterval)
13481366
let earliestEffectDate = Date(timeInterval: .hours(-24), since: now())
13491367
let nextEffectDate = insulinCounteractionEffects.last?.endDate ?? earliestEffectDate
1368+
let insulinEffectStartDate = nextEffectDate.addingTimeInterval(.minutes(-5))
13501369

13511370
let updateGroup = DispatchGroup()
13521371
let effectCalculationError = Locked<Error?>(nil)
13531372

13541373
var insulinEffect: [GlucoseEffect]?
13551374
let basalDosingEnd = includingPendingInsulin ? nil : now()
13561375
updateGroup.enter()
1357-
doseStore.getGlucoseEffects(start: nextEffectDate, end: nil, basalDosingEnd: basalDosingEnd) { result in
1376+
doseStore.getGlucoseEffects(start: insulinEffectStartDate, end: nil, basalDosingEnd: basalDosingEnd) { result in
13581377
switch result {
13591378
case .failure(let error):
13601379
effectCalculationError.mutate { $0 = error }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"startDate": "2023-07-29T18:17:07Z",
4+
"quantity": 50
5+
}
6+
]

0 commit comments

Comments
 (0)