Commit cb3345b4 authored by Yann Garcia's avatar Yann Garcia
Browse files

Validation of meep-vis with TTF T027

parent d9fe3429
Loading
Loading
Loading
Loading
+20 −27
Original line number Diff line number Diff line
@@ -402,6 +402,7 @@ func initializeV2xMessageDistribution() (err error) {
	log.Info("+++ poaNameList: ", poaNameList)
	var validPoaNameList []string
	var ecgi_s []string
	var ecgi_location_s [][]float32
	for _, poaName := range poaNameList {
		node := sbi.activeModel.GetNode(poaName)
		log.Info("+++ Processing node: ", node)
@@ -413,10 +414,11 @@ func initializeV2xMessageDistribution() (err error) {
				mnc := "" // TODO Apply numerical conversion directly, -1 if not initialized
				mcc := ""
				cellId := ""
				cellName := ""
				ecgi := ""
				zone := ""
				var zoneCell []float32
				switch nl.Type_ {
				case mod.NodeTypePoa4G, mod.NodeTypePoa5G:
				case mod.NodeTypePoa4G, mod.NodeTypePoa5G: // Extract PLMN
					poaParent := sbi.activeModel.GetNodeParent(poaName)
					log.Info("+++ poaParent: ", poaParent)
					if zone, ok := poaParent.(*dataModel.Zone); ok {
@@ -428,9 +430,12 @@ func initializeV2xMessageDistribution() (err error) {
								mnc = domain.CellularDomainConfig.Mnc
								mcc = domain.CellularDomainConfig.Mcc
								cellId = domain.CellularDomainConfig.DefaultCellId
								// TODO FSCOM Set broker at Zone node level
							}
						}
					}
					zoneCell = nl.GeoData.Location.Coordinates // e.g. [ 7.420433, 43.729942 ]
					cellName = nl.Name
					if nl.Poa4GConfig != nil {
						cellId = nl.Poa4GConfig.CellId
					} else if nl.Poa5GConfig != nil {
@@ -439,10 +444,11 @@ func initializeV2xMessageDistribution() (err error) {
					if len(cellId)%2 != 0 {
						cellId = "0" + cellId
					}
					log.Info("=================> cellName: ", cellName)
					log.Info("=================> cellId: ", cellId)
					log.Info("=================> mnc: ", mnc)
					log.Info("=================> mcc: ", mcc)
					log.Info("=================> mcc: ", zone)
					log.Info("=================> zoneCell: ", zoneCell)
					// Calculate Ecgi
					cellId_num, err := strconv.Atoi(cellId)
					if err != nil {
@@ -483,11 +489,14 @@ func initializeV2xMessageDistribution() (err error) {
					log.Info("initializeV2xMessageDistribution: ecgi= ", ecgi)
				} // End of 'switch' statement
				ecgi_s = append(ecgi_s, ecgi)
				ecgi_location_s = append(ecgi_location_s, zoneCell)
			}
		}
	} // End of 'for' statement
	log.Info("initializeV2xMessageDistribution: ecgi_s= ", ecgi_s)
	err = sbi.trafficMgr.InitializeV2xMessageDistribution(sbi.poaList, validPoaNameList, ecgi_s)
	log.Info("initializeV2xMessageDistribution: ecgi_location_s= ", ecgi_location_s)

	err = sbi.trafficMgr.InitializeV2xMessageDistribution(sbi.poaList, validPoaNameList, ecgi_s, ecgi_location_s)
	if err != nil {
		log.Error(err.Error())
		return err
@@ -526,6 +535,13 @@ func GetPredictedPowerValues(hour int32, inRsrp int32, inRsrq int32, poaName str
	return outRsrp, outRsrq, err
}

/*
 * GetInfoUuUnicast process the uu_unicast_provisioning_info GETT request and sends the response
 * @param {struct} params HTTP request parameters
 * @param {struct} num_item contains the number of paraneters
 * @return {struct} UuUnicastProvisioningInfoProInfoUuUnicast initialized data structure
 * @see ETSI GS MEC 030 V3.1.1 (2023-03) Clause 7.3.3.1 GET
 */
func GetInfoUuUnicast(params []string, num_item int) (proInfoUuUnicast UuUnicastProvisioningInfoProInfoUuUnicast_list, err error) {
	proInfoUuUnicast = nil
	resp, err := sbi.trafficMgr.GetInfoUuUnicast(params, num_item)
@@ -589,29 +605,6 @@ func GetInfoUuUnicast(params []string, num_item int) (proInfoUuUnicast UuUnicast
			}
		} // End of 'for' statement
	}
	// } else if params[0] == "latitude" {
	// 	// var geocoordinatesList gisClient.GeoCoordinateList
	// 	// geocoordinatesList.GeoCoordinates = geocoordinates
	// 	// powerResp, _, err := gisAppClient.GeospatialDataApi.GetGeoDataPowerValues(context.TODO(), geocoordinatesList)
	// 	// log.Info("GetInfoUuUnicast: powerResp= ", powerResp)
	// 	// if err != nil {
	// 	// 	err = errors.New("GetInfoUuUnicast: GetGeoDataPowerValues failed")
	// 	// 	log.Error(err.Error())
	// 	// 	return proInfoUuUnicast, err
	// 	// }
	// 	proInfoUuUnicast = make([]UuUnicastProvisioningInfoProInfoUuUnicast, len(resp))
	// 	proInfoUuUnicast[0].LocationInfo = new(LocationInfo)
	// 	proInfoUuUnicast[0].LocationInfo.Ecgi = nil
	// 	proInfoUuUnicast[0].LocationInfo.GeoArea = nil
	// 	proInfoUuUnicast[0].NeighbourCellInfo = nil
	// 	err = errors.New("GetInfoUuUnicast: Location not supported yet")
	// 	log.Error(err.Error())
	// 	return proInfoUuUnicast, err
	// } else {
	// 	err = errors.New("GetInfoUuUnicast: Invalid parameter: " + params[0])
	// 	log.Error(err.Error())
	// 	return proInfoUuUnicast, err
	// }

	log.Info("GetInfoUuUnicast: proInfoUuUnicast= ", proInfoUuUnicast)
	return proInfoUuUnicast, err
+768 −752

File changed.

Preview size limit exceeded, changes collapsed.

+3 −3
Original line number Diff line number Diff line
@@ -2210,8 +2210,8 @@ func TestFailV2xMsgDistributionServerPost(t *testing.T) {
	}
	fmt.Println("Request done")

	expected_v2xMsgDistributionServerInfo.V2xMsgDistributionServer[0].infoProtocol.msgProtocol = make([]int32, 0) // No message protocol
	body, err := json.Marshal(expected_v2xMsgDistributionServerInfo)                                              // Error: InfoConnection field is present :(
	expected_v2xMsgDistributionServerInfo.V2xMsgDistributionServer[0].InfoProtocol.MsgProtocol = make([]int32, 0) // No message protocol
	body, err = json.Marshal(expected_v2xMsgDistributionServerInfo)                                               // Error: InfoConnection field is present :(
	if err != nil {
		t.Fatalf(err.Error())
	}
@@ -2222,7 +2222,7 @@ func TestFailV2xMsgDistributionServerPost(t *testing.T) {
	fmt.Println("Request done")

	expected_v2xMsgDistributionServerInfo.V2xMsgDistributionServer = make([]V2xMsgDistributionServer, 0) // No V2xMsgDistributionServer
	body, err := json.Marshal(expected_v2xMsgDistributionServerInfo)                                     // Error: InfoConnection field is present :(
	body, err = json.Marshal(expected_v2xMsgDistributionServerInfo)                                      // Error: InfoConnection field is present :(
	if err != nil {
		t.Fatalf(err.Error())
	}
+151 −31
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ type V2xServerUsdTmgi struct {
var brokerRunning bool = false
var v2xPoaListMap map[string]string = nil
var cellName2CellIdMap map[string]string = nil
var cellId2LocationMap map[string][]float32 = nil
var cellId2CellNameMap map[string]string = nil

// DB Config
@@ -790,10 +791,11 @@ func (tm *TrafficMgr) GetPoaCategory(longitude float32, latitude float32) (categ
	return category, err
}

func (tm *TrafficMgr) InitializeV2xMessageDistribution(v2xPoaList []string, poaNameList []string, ecgi_s []string) (err error) {
func (tm *TrafficMgr) InitializeV2xMessageDistribution(v2xPoaList []string, poaNameList []string, ecgi_s []string, location_s [][]float32) (err error) {
	log.Info(">>> InitializeV2xMessageDistribution: v2xPoaList: ", v2xPoaList)
	log.Info(">>> InitializeV2xMessageDistribution: poaNameList: ", poaNameList)
	log.Info(">>> InitializeV2xMessageDistribution: ecgi_s: ", ecgi_s)
	log.Info(">>> InitializeV2xMessageDistribution: location_s: ", location_s)

	// Validate input
	if poaNameList == nil {
@@ -809,13 +811,15 @@ func (tm *TrafficMgr) InitializeV2xMessageDistribution(v2xPoaList []string, poaN
		cellName2CellIdMap = make(map[string]string, len(ecgi_s))
		cellId2CellNameMap = make(map[string]string, len(ecgi_s))
		v2xPoaListMap = make(map[string]string, len(ecgi_s))
		cellId2LocationMap = make(map[string][]float32, len(ecgi_s))
		for i := 0; i < len(ecgi_s); i++ {
			if ecgi_s[i] != "" {
				idx := sort.Search(len(tm.poa_list), func(j int) bool { return poaNameList[i] <= tm.poa_list[j] })
				if idx < len(tm.poa_list) {
					cellName2CellIdMap[poaNameList[i]] = ecgi_s[i]
					cellId2LocationMap[ecgi_s[i]] = location_s[i]
					cellId2CellNameMap[ecgi_s[i]] = poaNameList[i]
					// FIXME FSCOM Build the ist of V2X compliant PoA
					// FIXME FSCOM Build the list of V2X compliant PoA
					res := func() bool {
						for _, s := range v2xPoaList {
							if s == poaNameList[i] {
@@ -824,13 +828,14 @@ func (tm *TrafficMgr) InitializeV2xMessageDistribution(v2xPoaList []string, poaN
						} // End of 'for' statement
						return false
					}()
					if res == true {
					if res {
						v2xPoaListMap[ecgi_s[i]] = poaNameList[i]
					}
				}
			}
		} // End of 'for' statement
		log.Info("InitializeV2xMessageDistribution: cellName2CellIdMap: ", cellName2CellIdMap)
		log.Info("InitializeV2xMessageDistribution: cellId2LocationMap: ", cellId2LocationMap)
		log.Info("InitializeV2xMessageDistribution: cellId2CellNameMap: ", cellId2CellNameMap)
		log.Info("InitializeV2xMessageDistribution: v2xPoaListMap: ", v2xPoaListMap)
	} else {
@@ -932,43 +937,45 @@ func findReducedSignalStrength(inRsrp int32, inRsrq int32, users int32, averageL
	}
}

/*
 * GetInfoUuUnicast process the uu_unicast_provisioning_info GETT request and sends the response
 * @param {struct} params HTTP request parameters
 * @param {struct} num_item contains the number of paraneters
 * @see ETSI GS MEC 030 V3.1.1 (2023-03) Clause 7.3.3.1 GET
 */
func (tm *TrafficMgr) GetInfoUuUnicast(params []string, num_item int) (proInfoUuUnicast UuUnicastProvisioningInfoProInfoUuUnicast_list, err error) {
	log.Info(">>> GetInfoUuUnicast: params: ", params)
	log.Info(">>> GetInfoUuUnicast: num_item: ", num_item)

	proInfoUuUnicast = make([]UuUnicastProvisioningInfoProInfoUuUnicast, num_item)
	if params[0] == "ecgi" {
		for i := 1; i <= num_item; i++ {
		for i := 1; i <= num_item; i++ { // Same brocker for all Zone.
			// TODO To be enhance to have one broker per zone confgured in Zone node
			log.Info("GetInfoUuUnicast: Processing index #", i)

			ecgi_num, err := strconv.Atoi(params[i])
			// Find the ecgi in table
			var location_map []float32
			if val, ok := cellId2LocationMap[params[i]]; ok {
				location_map = val
				log.Info("GetInfoUuUnicast: location= ", location_map)
			} else {
				err = errors.New("Cannot find cell " + params[i])
				log.Error(err.Error())
				return nil, err
			}
			log.Info("GetInfoUuUnicast: location= ", location_map)

			ecgi, err := build_ecgi(params[i])
			if err != nil {
				log.Error(err.Error())
				return nil, err
			}
			log.Info("GetInfoUuUnicast: ecgi_num= ", ecgi_num)

			// Extract Poa CellId according to v2x_msg GS MEC 030 Clause 6.5.5 Type: Ecgi
			TwentyEigthBits := 0xFFFFFFF //  TS 36.413: E-UTRAN Cell Identity (ECI) and E-UTRAN Cell Global Identification (ECGI)
			eci := ecgi_num & TwentyEigthBits
			log.Info("GetInfoUuUnicast: eci= ", int(eci))
			// Extract Poa Plmn according to v2x_msg GS MEC 030 Clause 6.5.4 Type: Plmn
			plmn_num := int(ecgi_num >> 28)
			//log.Info("GetInfoUuUnicast: plmn= ", plmn_num)
			//mcc_num := int((plmn_num / 1000) & 0xFFFFFF)
			//mnc_num := int((plmn_num - mcc_num * 1000) & 0xFFFFFF)
			mcc_num := int(plmn_num / 1000)
			mnc_num := int(plmn_num - mcc_num*1000)
			//log.Info("GetInfoUuUnicast: mcc_num= ", mcc_num)
			//log.Info("GetInfoUuUnicast: mnc_num= ", mnc_num)
			// FIXME FSCOM How to manage neighbour cellIs
			uuUniNeighbourCellInfo := make([]UuUniNeighbourCellInfo, 0)
			//uuUniNeighbourCellInfo := make([]UuUniNeighbourCellInfo, 1)
			//uuUniNeighbourCellInfo[0] = UuUniNeighbourCellInfo{&ecgi, nil, 0, &plmn, nil}

			ecgi := Ecgi{
				CellId: &CellId{CellId: strconv.Itoa(int(eci))},
				Plmn:   &Plmn{Mcc: strconv.Itoa(int(mcc_num)), Mnc: strconv.Itoa(int(mnc_num))},
			}
			plmn := Plmn{Mcc: strconv.Itoa(int(mcc_num)), Mnc: strconv.Itoa(int(mnc_num))}
			uuUniNeighbourCellInfo := make([]UuUniNeighbourCellInfo, 1)
			uuUniNeighbourCellInfo[0] = UuUniNeighbourCellInfo{&ecgi, nil, 0, &plmn, nil}
			var v2xApplicationServer *V2xApplicationServer = nil
			if _, found := cellId2CellNameMap[params[i]]; found {
				u, err := url.ParseRequestURI(tm.broker)
@@ -982,17 +989,57 @@ func (tm *TrafficMgr) GetInfoUuUnicast(params []string, num_item int) (proInfoUu
					UdpPort:   u.Port(),
				}
			}
			proInfoUuUnicast[i-1] = UuUnicastProvisioningInfoProInfoUuUnicast{nil, uuUniNeighbourCellInfo, v2xApplicationServer}

			locationInfoGeoArea := &LocationInfoGeoArea{location_map[1], location_map[0]}
			locationInfo := &LocationInfo{&ecgi, locationInfoGeoArea}
			proInfoUuUnicast[i-1] = UuUnicastProvisioningInfoProInfoUuUnicast{locationInfo, uuUniNeighbourCellInfo, v2xApplicationServer}
		} // End of 'for' statement
	} else if params[0] == "latitude" {
		log.Info("GetInfoUuUnicast: Params is latitude")
		// FIXME Add logic based on position:
		// FIXME FSCOM Add logic based on position:
		//	1) Find the POA closest to the position
		//  2) Verify if it provides V2X services
		//  3) Uodate the data structures accordingly
		for i := 1; i <= num_item; i++ {
			log.Info("GetInfoUuUnicast: Processing index #", i)
			log.Info("GetInfoUuUnicast: params[i]: ", params[i])
			log.Info("GetInfoUuUnicast: params[i + num_item + 1]: ", params[i+num_item+1])

			lat, err := strconv.ParseFloat(params[i], 32)
			if err != nil {
				log.Error(err.Error())
				return nil, err
			}
			long, err := strconv.ParseFloat(params[i+num_item+1], 32)
			if err != nil {
				log.Error(err.Error())
				return nil, err
			}
			var min_distance float64 = math.MaxFloat64
			var selected_ecgi string = ""
			for idx, coord := range cellId2LocationMap {
				dist := distance_gps_distance_in_meters(float64(lat), float64(long), float64(coord[1]), float64(coord[0]))
				if dist < min_distance {
					min_distance = dist
					selected_ecgi = idx
					log.Info("GetInfoUuUnicast: min_distance: ", min_distance)
					log.Info("GetInfoUuUnicast: selected_ecgi: ", selected_ecgi)
				}
			} // End of 'for'statement
			if selected_ecgi == "" {
				err = errors.New("Failed to get the closest cell")
				log.Error(err.Error())
				return nil, err
			}

			ecgi, err := build_ecgi(selected_ecgi)
			if err != nil {
				log.Error(err.Error())
				return nil, err
			}

			locationInfoGeoArea := &LocationInfoGeoArea{cellId2LocationMap[selected_ecgi][1], cellId2LocationMap[selected_ecgi][0]}
			locationInfo := &LocationInfo{&ecgi, locationInfoGeoArea}
			var v2xApplicationServer *V2xApplicationServer = nil
			u, err := url.ParseRequestURI(tm.broker)
			log.Info("GetInfoUuUnicast: u: ", u)
@@ -1006,17 +1053,90 @@ func (tm *TrafficMgr) GetInfoUuUnicast(params []string, num_item int) (proInfoUu
				UdpPort:   u.Port(),
			}
			log.Info("GetInfoUuUnicast: v2xApplicationServer: ", *v2xApplicationServer)
			proInfoUuUnicast[i-1] = UuUnicastProvisioningInfoProInfoUuUnicast{nil, make([]UuUniNeighbourCellInfo, 0), v2xApplicationServer}
			proInfoUuUnicast[i-1] = UuUnicastProvisioningInfoProInfoUuUnicast{locationInfo, make([]UuUniNeighbourCellInfo, 0), v2xApplicationServer}
		} // End of 'for' statement
	} else {
		err = errors.New("GetInfoUuUnicast: Invalid parameter: " + params[0])
		proInfoUuUnicast = nil
		return nil, err
	}

	log.Info("GetInfoUuUnicast: proInfoUuUnicast= ", proInfoUuUnicast)
	log.Info("<<< GetInfoUuUnicast: proInfoUuUnicast= ", proInfoUuUnicast)
	return proInfoUuUnicast, nil
}

/*
 * build_ecgi build an Ecgi data structure based on the ECGI name
 * @param {string} ecgi_str the ECGI name
 * @return {struct} an initialized Ecgi data structure
 */
func build_ecgi(ecgi_str string) (ecgi Ecgi, err error) {
	log.Info(">>> build_ecgi: ecgi_str= ", ecgi_str)

	ecgi_num, err := strconv.Atoi(ecgi_str)
	if err != nil {
		log.Error(err.Error())
		return ecgi, err
	}
	log.Info("build_ecgi: ecgi_num= ", ecgi_num)

	// Extract Poa CellId according to v2x_msg GS MEC 030 Clause 6.5.5 Type: Ecgi
	TwentyEigthBits := 0xFFFFFFF //  TS 36.413: E-UTRAN Cell Identity (ECI) and E-UTRAN Cell Global Identification (ECGI)
	eci := ecgi_num & TwentyEigthBits
	log.Info("build_ecgi: eci= ", int(eci))
	// Extract Poa Plmn according to v2x_msg GS MEC 030 Clause 6.5.4 Type: Plmn
	plmn_num := int(ecgi_num >> 28)
	//log.Info("build_ecgi: plmn= ", plmn_num)
	//mcc_num := int((plmn_num / 1000) & 0xFFFFFF)
	//mnc_num := int((plmn_num - mcc_num * 1000) & 0xFFFFFF)
	mcc_num := int(plmn_num / 1000)
	mnc_num := int(plmn_num - mcc_num*1000)
	//log.Info("build_ecgi: mcc_num= ", mcc_num)
	//log.Info("build_ecgi: mnc_num= ", mnc_num)

	plmn := Plmn{Mcc: strconv.Itoa(int(mcc_num)), Mnc: strconv.Itoa(int(mnc_num))}
	ecgi = Ecgi{
		CellId: &CellId{CellId: strconv.Itoa(int(eci))},
		Plmn:   &plmn,
	}

	log.Info("<<< build_ecgi: ecgi= ", ecgi)
	return ecgi, nil
}

const EarthRadius float64 = 6378.1370
const Degrees2Rads float64 = math.Pi / float64(180.0)

/*
 * distance_gps_distance_in_km compute the heavyside distance in km between two GPS points (faster than addressing meep-gis-asset-mgr)
 * @param {float64} lat1 the latitude of point #1
 * @param {float64} long1 the longitude of point #1
 * @param {float64} lat2 the latitude of point #2
 * @param {float64} long2 the longitude of point #2
 * @return {float64} The distance in meter
 */
func distance_gps_distance_in_meters(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {
	return float64(1000.0) * distance_gps_distance_in_km(lat1, long1, lat2, long2)
}

/*
 * distance_gps_distance_in_km compute the heavyside distance in km between two GPS points (faster than addressing meep-gis-asset-mgr)
 * @param {float64} lat1 the latitude of point #1
 * @param {float64} long1 the longitude of point #1
 * @param {float64} lat2 the latitude of point #2
 * @param {float64} long2 the longitude of point #2
 * @return {float64} The distance in kmeter
 */
func distance_gps_distance_in_km(lat1 float64, long1 float64, lat2 float64, long2 float64) float64 {
	log.Info(">>> distance_gps_distance_in_km")
	dlong := float64((long2 - long1) * Degrees2Rads)
	dlat := float64((lat2 - lat1) * Degrees2Rads)
	a := math.Pow(math.Sin(dlat/2.0), 2.0) + math.Cos(lat1*Degrees2Rads)*math.Cos(lat2*Degrees2Rads)*math.Pow(math.Sin(dlong/2.0), 2.0)
	c := 2.0 * math.Atan2(math.Sqrt(a), math.Sqrt(1.0-a))
	d := EarthRadius * c
	log.Info("<<< distance_gps_distance_in_km: ", d)
	return d
}

func (tm *TrafficMgr) GetInfoUuMbmscast(params []string, num_item int) (proInfoUuMbmscast UuMbmsProvisioningInfoProInfoUuMbms_list, err error) {
	log.Info(">>> GetInfoUuMbmscast: params: ", params)
	log.Info(">>> GetInfoUuMbmscast: num_item: ", num_item)