Loading go-apps/meep-gis-engine/server/gis-automation.go +10 −3 Changes for go-apps/meep-gis-engine/server/gis-automation.go: 10 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,10 @@ func setAutomation(automationType string, state bool) (err error) { ge.updateTime = time.Time{} } } else if automationType == AutoTypeNetChar { if !state && ge.automation[AutoTypeNetChar] { if state && usesExternalNwSimulator() { log.Warn("NETWORK-CHARACTERISTICS-UPDATE not started: Simu5G/OAI network characteristics come from the Network Emulation Stack") state = false } else if !state && ge.automation[AutoTypeNetChar] && !usesExternalNwSimulator() { resetAutoNetChar() } } Loading Loading @@ -156,8 +159,9 @@ func runAutomation() { runAutoPoaInRange(ueMap) } // Network Characteristics if ge.automation[AutoTypeNetChar] { // Network Characteristics (distance-modulated throughput → sandbox-ctrl / TC). // Simu5G/OAI: the Network Emulation Stack owns latency/loss/throughput. if ge.automation[AutoTypeNetChar] && !usesExternalNwSimulator() { runAutoNetChar(ueMap, poaMap) } Loading Loading @@ -261,6 +265,9 @@ func runAutoPoaInRange(ueMap map[string]*am.Ue) { } func runAutoNetChar(ueMap map[string]*am.Ue, poaMap map[string]*am.Poa) { if usesExternalNwSimulator() { return } for _, ue := range ueMap { // Get stored UE info ueInfo := getUeInfo(ue.Name) Loading go-apps/meep-gis-engine/server/gis-engine.go +16 −10 Changes for go-apps/meep-gis-engine/server/gis-engine.go: 16 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -941,25 +941,24 @@ func updateCache() { } // Update POA measurements if different from cached value externalRadio := usesExternalNwSimulator() for _, poaMeas := range ue.PoaMeasurements { updateRequired := false cachedPoaMeas, found := cachedPoaMeasMap[ue.Name] var cachedMeas *gc.PoaMeasurement if found { cachedMeas, found = cachedPoaMeas.Measurements[poaMeas.Poa] } if !found { updateRequired = true } else { cachedMeas, found := cachedPoaMeas.Measurements[poaMeas.Poa] if !found || cachedMeas.Distance != poaMeas.Distance || cachedMeas.Rssi != poaMeas.Rssi || cachedMeas.Rsrp != poaMeas.Rsrp || cachedMeas.Rsrq != poaMeas.Rsrq { } else if cachedMeas.Distance != poaMeas.Distance { updateRequired = true } else if !externalRadio && (cachedMeas.Rssi != poaMeas.Rssi || cachedMeas.Rsrp != poaMeas.Rsrp || cachedMeas.Rsrq != poaMeas.Rsrq) { updateRequired = true } } if updateRequired { measurement := &gc.PoaMeasurement{ Rssi: poaMeas.Rssi, Rsrp: poaMeas.Rsrp, Rsrq: poaMeas.Rsrq, Distance: poaMeas.Distance, } measurement := mergePoaMeasurementForCache(externalRadio, poaMeas.Distance, poaMeas.Rssi, poaMeas.Rsrp, poaMeas.Rsrq, cachedMeas) _ = ge.gisCache.SetPoaMeasurement(ue.Name, AssetTypeUe, poaMeas.Poa, poaMeas.SubType, measurement) cacheUpdated = true } Loading Loading @@ -1737,6 +1736,13 @@ func geUpdateGeoDataByName(w http.ResponseWriter, r *http.Request) { } func geGetGeoDataPowerValues(w http.ResponseWriter, r *http.Request) { if usesExternalNwSimulator() { log.Info("cellularPower skipped: RSRP/RSRQ come from the Network Emulation Stack") w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) fmt.Fprint(w, `{"coordinatesPower":[]}`) return } // Retrieve coordinates to work with from request body var coordinates GeoCoordinateList if r.Body == nil { Loading go-apps/meep-gis-engine/server/gis_external_sim.go 0 → 100644 +82 −0 Changes for go-apps/meep-gis-engine/server/gis_external_sim.go: 82 added lines, 0 removed lines. Original line number Diff line number Diff line package server import ( "encoding/json" "os" "strings" gc "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-cache" mod "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model" ) func isExternalNwSimulatorType(t string) bool { switch strings.ToLower(strings.TrimSpace(t)) { case "simu5g", "oai": return true default: return false } } func userMetaExternalNwSimulator(userMeta map[string]string) bool { if userMeta == nil { return false } if raw, ok := userMeta["network-info"]; ok && raw != "" { var info struct { Type string `json:"type"` } if json.Unmarshal([]byte(raw), &info) == nil && isExternalNwSimulatorType(info.Type) { return true } } if raw, ok := userMeta["mec-sandbox"]; ok && raw != "" { var ms struct { ConnectivityModel string `json:"connectivityModel"` } if json.Unmarshal([]byte(raw), &ms) == nil && isExternalNwSimulatorType(ms.ConnectivityModel) { return true } } return false } // usesExternalNwSimulator is true when the platform catalog is Simu5G/OAI // or the active scenario userMeta says the Network Emulation Stack owns radio/net-char. func usesExternalNwSimulator() bool { if isExternalNwSimulatorType(os.Getenv("MEEP_NW_SIMULATOR_TYPE")) { return true } if ge == nil || ge.activeModel == nil { return false } dep := ge.activeModel.GetDeployment(&mod.NodeFilter{ExcludeChildren: true}) if dep == nil { return false } return userMetaExternalNwSimulator(dep.UserMeta) } // mergePoaMeasurementForCache keeps GIS-cache radio fields owned by the // Network Emulation Stack (Simu5G/OAI). Distance still comes from PostGIS. func mergePoaMeasurementForCache(external bool, distance, rssi, rsrp, rsrq float32, cached *gc.PoaMeasurement) *gc.PoaMeasurement { m := &gc.PoaMeasurement{ Distance: distance, Rssi: rssi, Rsrp: rsrp, Rsrq: rsrq, } if !external { return m } if cached != nil { m.Rssi = cached.Rssi m.Rsrp = cached.Rsrp m.Rsrq = cached.Rsrq } else { m.Rssi = 0 m.Rsrp = 0 m.Rsrq = 0 } return m } go-apps/meep-gis-engine/server/gis_external_sim_test.go 0 → 100644 +71 −0 Changes for go-apps/meep-gis-engine/server/gis_external_sim_test.go: 71 added lines, 0 removed lines. Original line number Diff line number Diff line package server import ( "os" "testing" gc "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-cache" ) func TestIsExternalNwSimulatorType(t *testing.T) { if !isExternalNwSimulatorType("simu5g") || !isExternalNwSimulatorType("OAI") { t.Fatal("simu5g/oai must be external") } if isExternalNwSimulatorType("internal") || isExternalNwSimulatorType("") { t.Fatal("internal must not be external") } } func TestUserMetaExternalNwSimulator(t *testing.T) { if !userMetaExternalNwSimulator(map[string]string{ "network-info": `{"type": "simu5g", "path":""}`, }) { t.Fatal("network-info type simu5g") } if !userMetaExternalNwSimulator(map[string]string{ "mec-sandbox": `{"connectivityModel": "oai"}`, }) { t.Fatal("mec-sandbox connectivityModel oai") } if userMetaExternalNwSimulator(map[string]string{ "network-info": `{"type": "internal"}`, }) { t.Fatal("internal network-info") } if userMetaExternalNwSimulator(nil) { t.Fatal("nil userMeta") } } func TestMergePoaMeasurementForCache(t *testing.T) { cached := &gc.PoaMeasurement{Rssi: 11, Rsrp: -80, Rsrq: 12, Distance: 10} got := mergePoaMeasurementForCache(true, 50, 1, 2, 3, cached) if got.Distance != 50 || got.Rssi != 11 || got.Rsrp != -80 || got.Rsrq != 12 { t.Fatalf("external must keep cached radio and take new distance: %+v", got) } got = mergePoaMeasurementForCache(true, 50, 1, 2, 3, nil) if got.Distance != 50 || got.Rssi != 0 || got.Rsrp != 0 || got.Rsrq != 0 { t.Fatalf("external with empty cache must not store GIS-computed radio: %+v", got) } got = mergePoaMeasurementForCache(false, 50, 1, 2, 3, cached) if got.Distance != 50 || got.Rssi != 1 || got.Rsrp != 2 || got.Rsrq != 3 { t.Fatalf("internal must use GIS-computed radio: %+v", got) } } func TestUsesExternalNwSimulatorEnv(t *testing.T) { prev := os.Getenv("MEEP_NW_SIMULATOR_TYPE") defer os.Setenv("MEEP_NW_SIMULATOR_TYPE", prev) saved := ge ge = nil defer func() { ge = saved }() os.Setenv("MEEP_NW_SIMULATOR_TYPE", "simu5g") if !usesExternalNwSimulator() { t.Fatal("simu5g env must be external") } os.Setenv("MEEP_NW_SIMULATOR_TYPE", "internal") if usesExternalNwSimulator() { t.Fatal("internal env must not be external") } } go-apps/meep-platform-ctrl/server/platform-ctrl.go +1 −1 Changes for go-apps/meep-platform-ctrl/server/platform-ctrl.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -422,7 +422,7 @@ func pcGetScenarioList(w http.ResponseWriter, r *http.Request) { nemList, nemErr = pfmCtrl.nwCatalog.ListNemScenarios(r.Context()) if nemErr != nil { log.Error("NEM scenario catalog: ", nemErr.Error()) http.Error(w, nemErr.Error(), http.StatusBadGateway) http.Error(w, nwcat.ErrMsgNemNotRunning, http.StatusBadGateway) return } } Loading Loading
go-apps/meep-gis-engine/server/gis-automation.go +10 −3 Changes for go-apps/meep-gis-engine/server/gis-automation.go: 10 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,10 @@ func setAutomation(automationType string, state bool) (err error) { ge.updateTime = time.Time{} } } else if automationType == AutoTypeNetChar { if !state && ge.automation[AutoTypeNetChar] { if state && usesExternalNwSimulator() { log.Warn("NETWORK-CHARACTERISTICS-UPDATE not started: Simu5G/OAI network characteristics come from the Network Emulation Stack") state = false } else if !state && ge.automation[AutoTypeNetChar] && !usesExternalNwSimulator() { resetAutoNetChar() } } Loading Loading @@ -156,8 +159,9 @@ func runAutomation() { runAutoPoaInRange(ueMap) } // Network Characteristics if ge.automation[AutoTypeNetChar] { // Network Characteristics (distance-modulated throughput → sandbox-ctrl / TC). // Simu5G/OAI: the Network Emulation Stack owns latency/loss/throughput. if ge.automation[AutoTypeNetChar] && !usesExternalNwSimulator() { runAutoNetChar(ueMap, poaMap) } Loading Loading @@ -261,6 +265,9 @@ func runAutoPoaInRange(ueMap map[string]*am.Ue) { } func runAutoNetChar(ueMap map[string]*am.Ue, poaMap map[string]*am.Poa) { if usesExternalNwSimulator() { return } for _, ue := range ueMap { // Get stored UE info ueInfo := getUeInfo(ue.Name) Loading
go-apps/meep-gis-engine/server/gis-engine.go +16 −10 Changes for go-apps/meep-gis-engine/server/gis-engine.go: 16 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -941,25 +941,24 @@ func updateCache() { } // Update POA measurements if different from cached value externalRadio := usesExternalNwSimulator() for _, poaMeas := range ue.PoaMeasurements { updateRequired := false cachedPoaMeas, found := cachedPoaMeasMap[ue.Name] var cachedMeas *gc.PoaMeasurement if found { cachedMeas, found = cachedPoaMeas.Measurements[poaMeas.Poa] } if !found { updateRequired = true } else { cachedMeas, found := cachedPoaMeas.Measurements[poaMeas.Poa] if !found || cachedMeas.Distance != poaMeas.Distance || cachedMeas.Rssi != poaMeas.Rssi || cachedMeas.Rsrp != poaMeas.Rsrp || cachedMeas.Rsrq != poaMeas.Rsrq { } else if cachedMeas.Distance != poaMeas.Distance { updateRequired = true } else if !externalRadio && (cachedMeas.Rssi != poaMeas.Rssi || cachedMeas.Rsrp != poaMeas.Rsrp || cachedMeas.Rsrq != poaMeas.Rsrq) { updateRequired = true } } if updateRequired { measurement := &gc.PoaMeasurement{ Rssi: poaMeas.Rssi, Rsrp: poaMeas.Rsrp, Rsrq: poaMeas.Rsrq, Distance: poaMeas.Distance, } measurement := mergePoaMeasurementForCache(externalRadio, poaMeas.Distance, poaMeas.Rssi, poaMeas.Rsrp, poaMeas.Rsrq, cachedMeas) _ = ge.gisCache.SetPoaMeasurement(ue.Name, AssetTypeUe, poaMeas.Poa, poaMeas.SubType, measurement) cacheUpdated = true } Loading Loading @@ -1737,6 +1736,13 @@ func geUpdateGeoDataByName(w http.ResponseWriter, r *http.Request) { } func geGetGeoDataPowerValues(w http.ResponseWriter, r *http.Request) { if usesExternalNwSimulator() { log.Info("cellularPower skipped: RSRP/RSRQ come from the Network Emulation Stack") w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) fmt.Fprint(w, `{"coordinatesPower":[]}`) return } // Retrieve coordinates to work with from request body var coordinates GeoCoordinateList if r.Body == nil { Loading
go-apps/meep-gis-engine/server/gis_external_sim.go 0 → 100644 +82 −0 Changes for go-apps/meep-gis-engine/server/gis_external_sim.go: 82 added lines, 0 removed lines. Original line number Diff line number Diff line package server import ( "encoding/json" "os" "strings" gc "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-cache" mod "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model" ) func isExternalNwSimulatorType(t string) bool { switch strings.ToLower(strings.TrimSpace(t)) { case "simu5g", "oai": return true default: return false } } func userMetaExternalNwSimulator(userMeta map[string]string) bool { if userMeta == nil { return false } if raw, ok := userMeta["network-info"]; ok && raw != "" { var info struct { Type string `json:"type"` } if json.Unmarshal([]byte(raw), &info) == nil && isExternalNwSimulatorType(info.Type) { return true } } if raw, ok := userMeta["mec-sandbox"]; ok && raw != "" { var ms struct { ConnectivityModel string `json:"connectivityModel"` } if json.Unmarshal([]byte(raw), &ms) == nil && isExternalNwSimulatorType(ms.ConnectivityModel) { return true } } return false } // usesExternalNwSimulator is true when the platform catalog is Simu5G/OAI // or the active scenario userMeta says the Network Emulation Stack owns radio/net-char. func usesExternalNwSimulator() bool { if isExternalNwSimulatorType(os.Getenv("MEEP_NW_SIMULATOR_TYPE")) { return true } if ge == nil || ge.activeModel == nil { return false } dep := ge.activeModel.GetDeployment(&mod.NodeFilter{ExcludeChildren: true}) if dep == nil { return false } return userMetaExternalNwSimulator(dep.UserMeta) } // mergePoaMeasurementForCache keeps GIS-cache radio fields owned by the // Network Emulation Stack (Simu5G/OAI). Distance still comes from PostGIS. func mergePoaMeasurementForCache(external bool, distance, rssi, rsrp, rsrq float32, cached *gc.PoaMeasurement) *gc.PoaMeasurement { m := &gc.PoaMeasurement{ Distance: distance, Rssi: rssi, Rsrp: rsrp, Rsrq: rsrq, } if !external { return m } if cached != nil { m.Rssi = cached.Rssi m.Rsrp = cached.Rsrp m.Rsrq = cached.Rsrq } else { m.Rssi = 0 m.Rsrp = 0 m.Rsrq = 0 } return m }
go-apps/meep-gis-engine/server/gis_external_sim_test.go 0 → 100644 +71 −0 Changes for go-apps/meep-gis-engine/server/gis_external_sim_test.go: 71 added lines, 0 removed lines. Original line number Diff line number Diff line package server import ( "os" "testing" gc "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-cache" ) func TestIsExternalNwSimulatorType(t *testing.T) { if !isExternalNwSimulatorType("simu5g") || !isExternalNwSimulatorType("OAI") { t.Fatal("simu5g/oai must be external") } if isExternalNwSimulatorType("internal") || isExternalNwSimulatorType("") { t.Fatal("internal must not be external") } } func TestUserMetaExternalNwSimulator(t *testing.T) { if !userMetaExternalNwSimulator(map[string]string{ "network-info": `{"type": "simu5g", "path":""}`, }) { t.Fatal("network-info type simu5g") } if !userMetaExternalNwSimulator(map[string]string{ "mec-sandbox": `{"connectivityModel": "oai"}`, }) { t.Fatal("mec-sandbox connectivityModel oai") } if userMetaExternalNwSimulator(map[string]string{ "network-info": `{"type": "internal"}`, }) { t.Fatal("internal network-info") } if userMetaExternalNwSimulator(nil) { t.Fatal("nil userMeta") } } func TestMergePoaMeasurementForCache(t *testing.T) { cached := &gc.PoaMeasurement{Rssi: 11, Rsrp: -80, Rsrq: 12, Distance: 10} got := mergePoaMeasurementForCache(true, 50, 1, 2, 3, cached) if got.Distance != 50 || got.Rssi != 11 || got.Rsrp != -80 || got.Rsrq != 12 { t.Fatalf("external must keep cached radio and take new distance: %+v", got) } got = mergePoaMeasurementForCache(true, 50, 1, 2, 3, nil) if got.Distance != 50 || got.Rssi != 0 || got.Rsrp != 0 || got.Rsrq != 0 { t.Fatalf("external with empty cache must not store GIS-computed radio: %+v", got) } got = mergePoaMeasurementForCache(false, 50, 1, 2, 3, cached) if got.Distance != 50 || got.Rssi != 1 || got.Rsrp != 2 || got.Rsrq != 3 { t.Fatalf("internal must use GIS-computed radio: %+v", got) } } func TestUsesExternalNwSimulatorEnv(t *testing.T) { prev := os.Getenv("MEEP_NW_SIMULATOR_TYPE") defer os.Setenv("MEEP_NW_SIMULATOR_TYPE", prev) saved := ge ge = nil defer func() { ge = saved }() os.Setenv("MEEP_NW_SIMULATOR_TYPE", "simu5g") if !usesExternalNwSimulator() { t.Fatal("simu5g env must be external") } os.Setenv("MEEP_NW_SIMULATOR_TYPE", "internal") if usesExternalNwSimulator() { t.Fatal("internal env must not be external") } }
go-apps/meep-platform-ctrl/server/platform-ctrl.go +1 −1 Changes for go-apps/meep-platform-ctrl/server/platform-ctrl.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -422,7 +422,7 @@ func pcGetScenarioList(w http.ResponseWriter, r *http.Request) { nemList, nemErr = pfmCtrl.nwCatalog.ListNemScenarios(r.Context()) if nemErr != nil { log.Error("NEM scenario catalog: ", nemErr.Error()) http.Error(w, nemErr.Error(), http.StatusBadGateway) http.Error(w, nwcat.ErrMsgNemNotRunning, http.StatusBadGateway) return } } Loading