Commit 50ed4add authored by Kevin Di Lallo's avatar Kevin Di Lallo
Browse files

wais support for UE measurements & disconnected nodes

parent 8f66ad0d
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -123,6 +123,14 @@ func Run() (err error) {
	return nil
}

func Stop() (err error) {
	// Stop refresh loop
	stopRefreshTicker()

	sbi.mqLocal.UnregisterHandler(sbi.handlerId)
	return nil
}

func startRefreshTicker() {
	log.Debug("Starting refresh loop")
	sbi.refreshTicker = time.NewTicker(1000 * time.Millisecond)
@@ -348,14 +356,6 @@ func refreshPositions() {
	}
}

func Stop() (err error) {
	// Stop refresh loop
	stopRefreshTicker()

	sbi.mqLocal.UnregisterHandler(sbi.handlerId)
	return nil
}

func isUeConnected(name string) bool {
	node := sbi.activeModel.GetNode(name)
	if node != nil {
+135 −13
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package sbi

import (
	"time"

	dataModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-data-model"
	gc "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-cache"
	log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger"
@@ -31,7 +33,7 @@ type SbiCfg struct {
	RedisAddr      string
	PostgisHost    string
	PostgisPort    string
	UeDataCb       func(string, string, string)
	StaInfoCb      func(string, string, string, *int32)
	ApInfoCb       func(string, string, *float32, *float32, []string)
	ScenarioNameCb func(string)
	CleanUpCb      func()
@@ -43,7 +45,8 @@ type WaisSbi struct {
	handlerId               int
	activeModel             *mod.Model
	gisCache                *gc.GisCache
	updateUeDataCB          func(string, string, string)
	refreshTicker           *time.Ticker
	updateStaInfoCB         func(string, string, string, *int32)
	updateAccessPointInfoCB func(string, string, *float32, *float32, []string)
	updateScenarioNameCB    func(string)
	cleanUpCB               func()
@@ -60,7 +63,7 @@ func Init(cfg SbiCfg) (err error) {
	}
	sbi = new(WaisSbi)
	sbi.sandboxName = cfg.SandboxName
	sbi.updateUeDataCB = cfg.UeDataCb
	sbi.updateStaInfoCB = cfg.StaInfoCb
	sbi.updateAccessPointInfoCB = cfg.ApInfoCb
	sbi.updateScenarioNameCB = cfg.ScenarioNameCb
	sbi.cleanUpCB = cfg.CleanUpCb
@@ -112,14 +115,39 @@ func Run() (err error) {
		return err
	}

	// Start refresh loop
	startRefreshTicker()

	return nil
}

func Stop() (err error) {
	// Stop refresh loop
	stopRefreshTicker()

	sbi.mqLocal.UnregisterHandler(sbi.handlerId)
	return nil
}

func startRefreshTicker() {
	log.Debug("Starting refresh loop")
	sbi.refreshTicker = time.NewTicker(1000 * time.Millisecond)
	go func() {
		for range sbi.refreshTicker.C {
			refreshPositions()
			refreshMeasurements()
		}
	}()
}

func stopRefreshTicker() {
	if sbi.refreshTicker != nil {
		sbi.refreshTicker.Stop()
		sbi.refreshTicker = nil
		log.Debug("Refresh loop stopped")
	}
}

// Message Queue handler
func msgHandler(msg *mq.Msg, userData interface{}) {
	switch msg.Message {
@@ -147,46 +175,63 @@ func processActiveScenarioTerminate() {
}

func processActiveScenarioUpdate() {

	log.Debug("processActiveScenarioUpdate")

	formerUeNameList := sbi.activeModel.GetNodeNames("UE")
	// Get previous list of connected UEs
	prevUeNames := []string{}
	prevUeNameList := sbi.activeModel.GetNodeNames("UE")
	for _, name := range prevUeNameList {
		if isUeConnected(name) {
			prevUeNames = append(prevUeNames, name)
		}
	}

	sbi.activeModel.UpdateScenario()

	scenarioName := sbi.activeModel.GetScenarioName()
	sbi.updateScenarioNameCB(scenarioName)

	// Get all POA positions
	// Get all POA positions & UE measurments
	poaPositionMap, _ := sbi.gisCache.GetAllPositions(gc.TypePoa)
	ueMeasMap, _ := sbi.gisCache.GetAllMeasurements()

	// Update UE info
	ueNames := []string{}
	ueNameList := sbi.activeModel.GetNodeNames("UE")
	for _, name := range ueNameList {
		// Ignore disconnected UEs
		if !isUeConnected(name) {
			continue
		}
		ueNames = append(ueNames, name)

		// Update STA Info
		ueParent := sbi.activeModel.GetNodeParent(name)
		if poa, ok := ueParent.(*dataModel.NetworkLocation); ok {
			apMacId := ""
			var rssi *int32
			switch poa.Type_ {
			case mod.NodeTypePoaWifi:
				apMacId = poa.PoaWifiConfig.MacId
				rssi = getRssi(name, poa.Name, ueMeasMap)
			}
			ue := (sbi.activeModel.GetNode(name)).(*dataModel.PhysicalLocation)
			sbi.updateUeDataCB(name, ue.MacId, apMacId)
			sbi.updateStaInfoCB(name, ue.MacId, apMacId, rssi)
		}
	}

	//only find UEs that were removed, check that former UEs are in new UE list
	for _, oldUe := range formerUeNameList {
	// Update UEs that were removed
	for _, prevUeName := range prevUeNames {
		found := false
		for _, newUe := range ueNameList {
			if newUe == oldUe {
		for _, ueName := range ueNames {
			if ueName == prevUeName {
				found = true
				break
			}
		}
		if !found {
			sbi.updateUeDataCB(oldUe, oldUe, "")
			log.Info("Ue removed : ", oldUe)
			sbi.updateStaInfoCB(prevUeName, "", "", nil)
			log.Info("Ue removed : ", prevUeName)
		}
	}

@@ -214,3 +259,80 @@ func processActiveScenarioUpdate() {
		sbi.updateAccessPointInfoCB(name, poa.PoaWifiConfig.MacId, longitude, latitude, ueMacIdList)
	}
}

func refreshPositions() {
	// Update POA Positions
	poaPositionMap, _ := sbi.gisCache.GetAllPositions(gc.TypePoa)
	poaNameList := sbi.activeModel.GetNodeNames(mod.NodeTypePoaWifi)
	for _, name := range poaNameList {
		// Get Network Location
		poa := (sbi.activeModel.GetNode(name)).(*dataModel.NetworkLocation)
		if poa == nil {
			log.Error("Can't find poa named " + name)
			continue
		}

		// Get position
		var longitude *float32
		var latitude *float32
		if position, found := poaPositionMap[name]; found {
			longitude = &position.Longitude
			latitude = &position.Latitude
		}

		// Get list UE MacIds
		var ueMacIdList []string
		for _, pl := range poa.PhysicalLocations {
			ueMacIdList = append(ueMacIdList, pl.MacId)
		}

		sbi.updateAccessPointInfoCB(name, poa.PoaWifiConfig.MacId, longitude, latitude, ueMacIdList)
	}
}

func refreshMeasurements() {
	// Update UE measurements
	ueMeasMap, _ := sbi.gisCache.GetAllMeasurements()
	ueNameList := sbi.activeModel.GetNodeNames("UE")
	for _, name := range ueNameList {
		// Ignore disconnected UEs
		if !isUeConnected(name) {
			continue
		}

		// Update STA Info
		ueParent := sbi.activeModel.GetNodeParent(name)
		if poa, ok := ueParent.(*dataModel.NetworkLocation); ok {
			apMacId := ""
			var rssi *int32
			switch poa.Type_ {
			case mod.NodeTypePoaWifi:
				apMacId = poa.PoaWifiConfig.MacId
				rssi = getRssi(name, poa.Name, ueMeasMap)
			}
			ue := (sbi.activeModel.GetNode(name)).(*dataModel.PhysicalLocation)
			sbi.updateStaInfoCB(name, ue.MacId, apMacId, rssi)
		}
	}
}

func getRssi(ue string, poa string, ueMeasMap map[string]*gc.UeMeasurement) *int32 {
	if ueMeas, ueFound := ueMeasMap[ue]; ueFound {
		if meas, poaFound := ueMeas.Measurements[poa]; poaFound {
			rssi := int32(meas.Rssi)
			return &rssi
		}
	}
	return nil
}

func isUeConnected(name string) bool {
	node := sbi.activeModel.GetNode(name)
	if node != nil {
		pl := node.(*dataModel.PhysicalLocation)
		if pl.Connected {
			return true
		}
	}
	return false
}
+3 −23
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import (
)

func convertJsonToApInfoComplete(jsonInfo string) *ApInfoComplete {

	var obj ApInfoComplete
	err := json.Unmarshal([]byte(jsonInfo), &obj)
	if err != nil {
@@ -34,19 +33,16 @@ func convertJsonToApInfoComplete(jsonInfo string) *ApInfoComplete {
}

func convertApInfoCompleteToJson(obj *ApInfoComplete) string {

	jsonInfo, err := json.Marshal(*obj)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	return string(jsonInfo)
}

func convertJsonToUeData(jsonData string) *UeData {

	var obj UeData
func convertJsonToStaInfo(jsonData string) *StaInfo {
	var obj StaInfo
	err := json.Unmarshal([]byte(jsonData), &obj)
	if err != nil {
		log.Error(err.Error())
@@ -55,36 +51,20 @@ func convertJsonToUeData(jsonData string) *UeData {
	return &obj
}

func convertUeDataToJson(obj *UeData) string {

func convertStaInfoToJson(obj *StaInfo) string {
	jsonData, err := json.Marshal(*obj)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	return string(jsonData)
}

/* not used
func convertJsonToSubscription(jsonInfo string) *Subscription {

	var obj Subscription
	err := json.Unmarshal([]byte(jsonInfo), &obj)
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return &obj
}
*/
func convertSubscriptionToJson(obj *Subscription) string {

	jsonInfo, err := json.Marshal(*obj)
	if err != nil {
		log.Error(err.Error())
		return ""
	}

	return string(jsonInfo)
}
+61 −52
Original line number Diff line number Diff line
@@ -71,11 +71,6 @@ var expiryTicker *time.Ticker

var nextSubscriptionIdAvailable int

type UeData struct {
	ApMacId  string `json:"apMacId"`
	OwnMacId string `json:"macId"`
}

type ApInfoComplete struct {
	ApId       ApIdentity
	ApLocation ApLocation
@@ -144,7 +139,7 @@ func Init() (err error) {
	sbiCfg := sbi.SbiCfg{
		SandboxName:    sandboxName,
		RedisAddr:      redisAddr,
		UeDataCb:       updateUeData,
		StaInfoCb:      updateStaInfo,
		ApInfoCb:       updateApInfo,
		ScenarioNameCb: updateStoreName,
		CleanUpCb:      cleanUp,
@@ -179,28 +174,67 @@ func Stop() (err error) {
	return sbi.Stop()
}

func updateUeData(name string, ownMacId string, apMacId string) {
func updateStaInfo(name string, ownMacId string, apMacId string, rssi *int32) {

	oldApMacId := ""
	oldOwnMacId := ""
	// Get STA Info from DB, if any
	var staInfo *StaInfo
	jsonStaInfo, _ := rc.JSONGetEntry(baseKey+"UE:"+name, ".")
	if jsonStaInfo != "" {
		staInfo = convertJsonToStaInfo(jsonStaInfo)
	}

	//get from DB
	jsonUeData, _ := rc.JSONGetEntry(baseKey+"UE:"+name, ".")
	// Update DB if STA Info does not exist or has changed
	if isStaInfoUpdateRequired(staInfo, ownMacId, apMacId, rssi) {

	if jsonUeData != "" {
		ueDataObj := convertJsonToUeData(jsonUeData)
		if ueDataObj != nil {
			oldApMacId = ueDataObj.ApMacId
			oldOwnMacId = ueDataObj.OwnMacId
		// Set STA Mac ID
		if staInfo == nil {
			staInfo = new(StaInfo)
			staInfo.StaId = new(StaIdentity)
		}
		staInfo.StaId.MacId = ownMacId

		// Set Associated AP, if any
		if apMacId == "" {
			staInfo.ApAssociated = nil
		} else {
			if staInfo.ApAssociated == nil {
				staInfo.ApAssociated = new(ApAssociated)
			}
	//updateDB if changes occur
	if oldApMacId != apMacId || oldOwnMacId != ownMacId || name == "10.10.0.2" {
		var ueData UeData
		ueData.ApMacId = apMacId
		ueData.OwnMacId = ownMacId
		_ = rc.JSONSetEntry(baseKey+"UE:"+name, ".", convertUeDataToJson(&ueData))
			staInfo.ApAssociated.MacId = apMacId
		}

		// Set RSSI
		if rssi == nil {
			staInfo.Rssi = 0
		} else {
			staInfo.Rssi = *rssi
		}

		// Update DB
		_ = rc.JSONSetEntry(baseKey+"UE:"+name, ".", convertStaInfoToJson(staInfo))
	}
}

func isStaInfoUpdateRequired(staInfo *StaInfo, ownMacId string, apMacId string, rssi *int32) bool {
	// Check if STA Info exists
	if staInfo == nil {
		return true
	}
	// Compare STA Mac
	if ownMacId != staInfo.StaId.MacId {
		return true
	}
	// Compare AP Mac
	if (apMacId == "" && staInfo.ApAssociated != nil) ||
		(apMacId != "" && (staInfo.ApAssociated == nil || apMacId != staInfo.ApAssociated.MacId)) {
		return true
	}
	// Compare RSSI
	if (rssi == nil && staInfo.Rssi != 0) ||
		(rssi != nil && *rssi != staInfo.Rssi) {
		return true
	}
	return false
}

func convertFloatToGeolocationFormat(value *float32) int32 {
@@ -716,50 +750,25 @@ func populateStaInfo(key string, jsonInfo string, response interface{}) error {
		return errors.New("Response not defined")
	}

	// Retrieve user info from DB
	var ueData UeData
	err := json.Unmarshal([]byte(jsonInfo), &ueData)
	if err != nil {
		return err
	}

	//if not connected to any wifi poa, ignore
	if ueData.ApMacId != "" {

	// Add STA info to reponse (ignore if not associated to a wifi AP)
	staInfo := convertJsonToStaInfo(jsonInfo)
	if staInfo.ApAssociated != nil {
		//timeStamp is optional, commenting the code
		//seconds := time.Now().Unix()
		//var timeStamp TimeStamp
		//timeStamp.Seconds = int32(seconds)

		var staInfo StaInfo
		//staInfo.TimeStamp = &timeStamp

		var staId StaIdentity
		staId.MacId = ueData.OwnMacId
		staInfo.StaId = &staId

		var apAssociated ApAssociated
		apAssociated.MacId = ueData.ApMacId
		staInfo.ApAssociated = &apAssociated

		//TODO put a value in rssi that is coming from postGIS
		//log.Info("TODO forced RSSI")
		//staInfo.Rssi = 121

		resp.StaInfo = append(resp.StaInfo, staInfo)

		resp.StaInfo = append(resp.StaInfo, *staInfo)
	}

	return nil
}

func staInfoGET(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")

	var response InlineResponse2001

	//loop through each AP
	// Loop through each STA
	keyName := baseKey + "UE:*"
	err := rc.ForEachJSONEntry(keyName, populateStaInfo, &response)
	if err != nil {
+10 −11
Original line number Diff line number Diff line
@@ -6440,14 +6440,13 @@ func TestSbi(t *testing.T) {
	ueName := "10.10.0.2"
	ueMacId := "101002000000" //currently name
	apName1 := "4g-macro-cell-10"
	apMacId1 := ""
	apName2 := "w10"
	apMacId2 := "0050C272800A"

	var expectedUeDataStr [2]string
	var expectedUeData [2]UeData
	expectedUeData[INITIAL] = UeData{apMacId1, ueMacId}
	expectedUeData[UPDATED] = UeData{apMacId2, ueMacId}
	var expectedStaInfoStr [2]string
	var expectedStaInfo [2]StaInfo
	expectedStaInfo[INITIAL] = StaInfo{StaId: &StaIdentity{MacId: ""}}
	expectedStaInfo[UPDATED] = StaInfo{StaId: &StaIdentity{MacId: ueMacId}, ApAssociated: &ApAssociated{MacId: apMacId2}}

	var expectedApInfoApIdMacIdStr [2]string
	var expectedApInfoNbStas [2]int
@@ -6456,17 +6455,17 @@ func TestSbi(t *testing.T) {
	expectedApInfoNbStas[INITIAL] = 0
	expectedApInfoNbStas[UPDATED] = 1

	j, err := json.Marshal(expectedUeData[INITIAL])
	j, err := json.Marshal(expectedStaInfo[INITIAL])
	if err != nil {
		t.Fatalf(err.Error())
	}
	expectedUeDataStr[INITIAL] = string(j)
	expectedStaInfoStr[INITIAL] = string(j)

	j, err = json.Marshal(expectedUeData[UPDATED])
	j, err = json.Marshal(expectedStaInfo[UPDATED])
	if err != nil {
		t.Fatalf(err.Error())
	}
	expectedUeDataStr[UPDATED] = string(j)
	expectedStaInfoStr[UPDATED] = string(j)

	/******************************
	 * execution section
@@ -6476,7 +6475,7 @@ func TestSbi(t *testing.T) {
	initialiseScenario(testScenario)

	jsonUeData, _ := rc.JSONGetEntry(baseKey+"UE:"+ueName, ".")
	if string(jsonUeData) != expectedUeDataStr[INITIAL] {
	if string(jsonUeData) != expectedStaInfoStr[INITIAL] {
		t.Fatalf("Failed to get expected response")
	}

@@ -6492,7 +6491,7 @@ func TestSbi(t *testing.T) {
	updateScenario("mobility1")

	jsonUeData, _ = rc.JSONGetEntry(baseKey+"UE:"+ueName, ".")
	if string(jsonUeData) != expectedUeDataStr[UPDATED] {
	if string(jsonUeData) != expectedStaInfoStr[UPDATED] {
		t.Fatalf("Failed to get expected response")
	}

Loading