In order to focus on problem-solving, I’ve decided to use Cobra+Viper to replace existing thereceipe/qt GUI.
Cobra: https://github.com/spf13/cobra
Viper: https://github.com/spf13/viper
For example:
- Use cmd ‘ngapp nrrg conf freqband -h’ to get help
D:\dev\go\src\github.com\zhenggao2\ngapp>ngapp nrrg conf freqband -h
nrrg conf freqband can be used to get/set frequency-band related network configurations.
Usage:
ngapp nrrg conf freqband [flags]
Flags:
--opBand string Operating band (default "n41")
-h, --help help for freqband
Global Flags:
-c, --config string config file (default is $HOME/.ngapp.yaml)
- Use cmd ‘ngapp nrrg conf freqband’ to get current settings:
D:\dev\go\src\github.com\zhenggao2\ngapp>ngapp nrrg conf freqband
Flag Type Current Value Modifiable
opBand string n41 true
_duplexMode string TDD false
_maxDlFreq int 2690 false
_freqRange string FR1 false
- Use cmd ‘ngapp nrrg conf freqband --opBand=n78’ to configure modifiable flag opBand:
D:\dev\go\src\github.com\zhenggao2\ngapp>ngapp nrrg conf freqband --opBand=n78
nrgrid.FreqBandInfo: {3300 MHz-3800 MHz 3300 MHz-3800 MHz TDD 3800}
Available SSB scs: 30KHz
RMSI scs(subcarrierSpacingCommon of MIB) range: 15KHz,30KHz
carrier scs(subcarrierSpacing of SCS-SpecificCarrier) range: 15KHz,30KHz,60KHz
nrgrid.RachInfo: {B4 2 [1] [9] 0 1 1 12}
PRACH scs(msg1-SubcarrierSpacing of RACH-ConfigCommon) range: 15KHz,30KHz
Flag Type Current Value Modifiable
opBand string n78 true
_duplexMode string TDD false
_maxDlFreq int 3800 false
_freqRange string FR1 false
Now I will introduce the framework:
- Former GUI settings are orgnized into separate sub-command:
// nrrgCmd.init
func init() {
nrrgConfCmd.AddCommand(confFreqBandCmd)
nrrgConfCmd.AddCommand(confSsbGridCmd)
nrrgConfCmd.AddCommand(confSsbBurstCmd)
nrrgConfCmd.AddCommand(confMibCmd)
nrrgConfCmd.AddCommand(confCarrierGridCmd)
nrrgConfCmd.AddCommand(confCommonSettingCmd)
nrrgConfCmd.AddCommand(confCss0Cmd)
nrrgConfCmd.AddCommand(confCoreset1Cmd)
nrrgConfCmd.AddCommand(confUssCmd)
nrrgConfCmd.AddCommand(confDci10Cmd)
nrrgConfCmd.AddCommand(confDci11Cmd)
nrrgConfCmd.AddCommand(confMsg3Cmd)
nrrgConfCmd.AddCommand(confDci01Cmd)
nrrgConfCmd.AddCommand(confBwpCmd)
nrrgConfCmd.AddCommand(confRachCmd)
nrrgConfCmd.AddCommand(confDmrsCommonCmd)
nrrgConfCmd.AddCommand(confDmrsPdschCmd)
nrrgConfCmd.AddCommand(confPtrsPdschCmd)
nrrgConfCmd.AddCommand(confDmrsPuschCmd)
nrrgConfCmd.AddCommand(confPtrsPuschCmd)
nrrgConfCmd.AddCommand(confPdschCmd)
nrrgConfCmd.AddCommand(confPuschCmd)
nrrgConfCmd.AddCommand(confNzpCsiRsCmd)
nrrgConfCmd.AddCommand(confTrsCmd)
nrrgConfCmd.AddCommand(confCsiImCmd)
nrrgConfCmd.AddCommand(confCsiReportCmd)
nrrgConfCmd.AddCommand(confSrsCmd)
nrrgConfCmd.AddCommand(confPucchCmd)
nrrgConfCmd.AddCommand(confAdvancedCmd)
nrrgCmd.AddCommand(nrrgConfCmd)
nrrgCmd.AddCommand(nrrgSimCmd)
rootCmd.AddCommand(nrrgCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// nrrgCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
initConfFreqBandCmd()
initConfSsbGridCmd()
initConfSsbBurstCmd()
initConfMibCmd()
initConfCarrierGridCmd()
initConfCommonSettingCmd()
initConfCss0Cmd()
initConfCoreset1Cmd()
initConfUssCmd()
initConfDci10Cmd()
initConfDci11Cmd()
initConfMsg3Cmd()
initConfDci01Cmd()
initConfBwpCmd()
initConfRachCmd()
initConfDmrsCommonCmd()
initConfDmrsPdschCmd()
initConfPtrsPdschCmd()
initConfDmrsPuschCmd()
initConfPtrsPuschCmd()
initConfPdschCmd()
initConfPuschCmd()
initConfNzpCsiRsCmd()
initConfTrsCmd()
initConfCsiImCmd()
initConfCsiReportCmd()
initConfSrsCmd()
initConfPucchCmd()
initConfAdvancedCmd()
}
Here is the example code for initConfFreqBandCmd:
- flags started with underscore(’_’) are hidden and are designed to be unmodifiable
- viper binding is orgnized as: app.subcmd.flags-of-subcmd, and configuration file is YAML format by default.
func initConfFreqBandCmd() {
confFreqBandCmd.Flags().StringVar(&flags.freqBand.opBand, "opBand", "n41", "Operating band")
confFreqBandCmd.Flags().StringVar(&flags.freqBand._duplexMode, "_duplexMode", "TDD", "Duplex mode")
confFreqBandCmd.Flags().IntVar(&flags.freqBand._maxDlFreq, "_maxDlFreq", 2690, "Maximum DL frequency(MHz)")
confFreqBandCmd.Flags().StringVar(&flags.freqBand._freqRange, "_freqRange", "FR1", "Frequency range(FR1/FR2)")
confFreqBandCmd.Flags().SortFlags = false
viper.BindPFlag("nrrg.freqBand.opBand", confFreqBandCmd.Flags().Lookup("opBand"))
viper.BindPFlag("nrrg.freqBand._duplexMode", confFreqBandCmd.Flags().Lookup("_duplexMode"))
viper.BindPFlag("nrrg.freqBand._maxDlFreq", confFreqBandCmd.Flags().Lookup("_maxDlFreq"))
viper.BindPFlag("nrrg.freqBand._freqRange", confFreqBandCmd.Flags().Lookup("_freqRange"))
confFreqBandCmd.Flags().MarkHidden("_duplexMode")
confFreqBandCmd.Flags().MarkHidden("_maxDlFreq")
confFreqBandCmd.Flags().MarkHidden("_freqRange")
}
- per subcmd implementation example:
- In PreRun, call loadFlags function to reload all flags from viper configuration file.
var confFreqBandCmd = &cobra.Command{
Use: "freqband",
Short: "",
Long: `nrrg conf freqband can be used to get/set frequency-band related network configurations.`,
PreRun: func(cmd *cobra.Command, args []string) {
loadFlags()
},
Run: func(cmd *cobra.Command, args []string) {
}
- In Run, implement procedures when certain flag is Changed.
- Use viper.WatchConfig() and viper.WriteConfig() to keep flags and viper configuration file synchronized.
Run: func(cmd *cobra.Command, args []string) {
viper.WatchConfig()
if cmd.Flags().Lookup("opBand").Changed {
band := flags.freqBand.opBand
p, exist := nrgrid.OpBands[band]
if !exist {
fmt.Println("Invalid frequency band(FreqBandIndicatorNR):", band)
return
}
if p.DuplexMode == "SUL" || p.DuplexMode == "SDL" {
fmt.Println(p.DuplexMode, "is not supported!")
return
}
fmt.Println("nrgrid.FreqBandInfo:", *p)
// update band info
flags.freqBand._duplexMode = p.DuplexMode
flags.freqBand._maxDlFreq = p.MaxDlFreq
v, _ := strconv.Atoi(band[1:])
if v >= 1 && v <= 256 {
flags.freqBand._freqRange = "FR1"
} else {
flags.freqBand._freqRange = "FR2"
}
// update ssb scs
var ssbScsSet []string
for _, v := range nrgrid.SsbRasters[band] {
ssbScsSet = append(ssbScsSet, v[0])
}
fmt.Println("Available SSB scs:", strings.Join(ssbScsSet, ","))
// update rmsi scs and carrier scs
var rmsiScsSet []string
var carrierScsSet []string
if flags.freqBand._freqRange == "FR1" {
rmsiScsSet = append(rmsiScsSet, []string{"15KHz", "30KHz"}...)
scsFr1 := []int{15, 30, 60}
for _, scs := range scsFr1 {
key := fmt.Sprintf("%v_%v", band, scs)
valid := false
for _, i := range nrgrid.BandScs2BwFr1[key] {
if i > 0 {
valid = true
break
}
}
if valid {
carrierScsSet = append(carrierScsSet, fmt.Sprintf("%vKHz", scs))
}
}
} else {
rmsiScsSet = append(rmsiScsSet, []string{"60KHz", "120KHz"}...)
carrierScsSet = append(carrierScsSet, []string{"60KHz", "120KHz"}...)
}
fmt.Println("RMSI scs(subcarrierSpacingCommon of MIB) range:", strings.Join(rmsiScsSet, ","))
fmt.Println("carrier scs(subcarrierSpacing of SCS-SpecificCarrier) range:", strings.Join(carrierScsSet, ","))
// update rach info
err := updateRach()
if err != nil {
fmt.Print(err.Error())
return
}
}
print(cmd, args)
viper.WriteConfig()
},
- Thoughts on Go vs Python:
I am actually translating former Python codes into Go codes. With the right Wheels, Go is more elegant and much more efficient than Python.
(to be continued)