From 566d4363beead21df0edcbf2655cdb3db5d3d1bb Mon Sep 17 00:00:00 2001 From: rokath Date: Mon, 14 Oct 2024 21:46:35 +0200 Subject: [PATCH] CLI switch -IDRange added, emitter "channels" renamed to "tags" --- internal/args/handler.go | 4 + internal/args/init.go | 6 +- internal/args/short_test.go | 15 --- internal/args/tricehelpall_test.go | 13 +- internal/emitter/emitter.go | 2 +- internal/emitter/lineTransformerANSI.go | 103 ++++++++------- internal/id/helper.go | 4 +- internal/id/range_test.go | 57 +++++++++ internal/id/switchIDs.go | 158 ++++++++++++++++++------ internal/link/link.go | 7 +- internal/translator/translator.go | 2 +- internal/trexDecoder/trexDecoder.go | 2 +- 12 files changed, 262 insertions(+), 111 deletions(-) create mode 100644 internal/id/range_test.go diff --git a/internal/args/handler.go b/internal/args/handler.go index aae89365b..566ecd3a2 100644 --- a/internal/args/handler.go +++ b/internal/args/handler.go @@ -94,6 +94,10 @@ func Handler(w io.Writer, fSys *afero.Afero, args []string) error { case "i", "insert": msg.OnErr(fsScInsert.Parse(subArgs)) id.CompactSrcs() + err := id.EvaluateIDRangeStrings() + if err != nil { + return err + } w = do.DistributeArgs(w, fSys, LogfileName, Verbose) return id.SubCmdIdInsert(w, fSys) // // case "zeroSourceTreeIds": diff --git a/internal/args/init.go b/internal/args/init.go index aeb8762ec..c76b3f756 100644 --- a/internal/args/init.go +++ b/internal/args/init.go @@ -205,9 +205,9 @@ func addInit() { // } func insertIDsInit() { - fsScInsert = flag.NewFlagSet("insertSourceTreeIds", flag.ExitOnError) // sub-command + fsScInsert = flag.NewFlagSet("insert", flag.ExitOnError) // sub-command flagsRefreshAndUpdate(fsScInsert) - // todo: flagTriceIDRange(fsScInsert) + flagTriceIDRange(fsScInsert) fsScInsert.Var(&id.Min, "IDMin", "Lower end of ID range for normal trices.") fsScInsert.Var(&id.Max, "IDMax", "Upper end of ID range for normal trices.") fsScInsert.IntVar(&id.DefaultStampSize, "defaultStampSize", 32, "Default stamp size for written TRICE macros without id(0), Id(0 or ID(0). Valid values are 0, 16 or 32.") @@ -246,7 +246,7 @@ func scanInit() { } func sdInit() { - fsScSdSv = flag.NewFlagSet("shutdownServer", flag.ExitOnError) // sub-command + fsScSdSv = flag.NewFlagSet("shutdown", flag.ExitOnError) // sub-command flagIPAddress(fsScSdSv) } diff --git a/internal/args/short_test.go b/internal/args/short_test.go index afa678a09..9ad92c7bc 100644 --- a/internal/args/short_test.go +++ b/internal/args/short_test.go @@ -13,21 +13,6 @@ import ( "github.com/tj/assert" ) -// func TestMain(m *testing.M) { -// id.FnJSON = getTemporaryFileName("til-*.JSON") -// code := m.Run() -// msg.OnErr(os.Remove(id.FnJSON)) -// os.Exit(code) // os.Exit() does not respect defer statements -// } - -func getTemporaryFileName(pattern string) string { - tempFileHandle, e := os.CreateTemp(os.TempDir(), pattern) // opens for read and write - msg.OnErr(e) - tempFileName := tempFileHandle.Name() - msg.OnErr(tempFileHandle.Close()) - return tempFileName -} - func TestHelp(t *testing.T) { args := []string{"trice", "help"} expect := `syntax: 'trice sub-command' [params] diff --git a/internal/args/tricehelpall_test.go b/internal/args/tricehelpall_test.go index 5e4a217c9..4114dd9fa 100644 --- a/internal/args/tricehelpall_test.go +++ b/internal/args/tricehelpall_test.go @@ -396,6 +396,15 @@ sub-command 'i|insert': For updating til.json and inserting IDs into source file Search method for new ID's in range- Options are 'upward', 'downward' & 'random'. (default "random") -IDMin value Lower end of ID range for normal trices. (default 1000) + -IDRange value + This allows channel specific routing in the target code. + This switch has one parameter string and is a multi-flag switch. It can be used for each Trice tag. Example: + Assign error tag Trice IDs in the range 10-99 and msg tag IDs in the range 100-199: + "trice insert -IDRange err:10,99 -IDRange msg:100,999" (overlapping ID ranges are forbidden) + All other trice tags get IDs from the -IDMin, -IDMax range. The used -IDMethod is the same for all tags. + For example you can have all trice messages in direct mode over RTT but err & msg tagged trices additionally + in deferred mode over a serial port and, if you need, store all error tagged Trice logs additionally in the Flash memory. + You need to configure the target code accordingly. (default "") -addParamCount Extend TRICE macro names with the parameter count _n to enable compile time checks. -cache @@ -404,7 +413,7 @@ sub-command 'i|insert': For updating til.json and inserting IDs into source file Default stamp size for written TRICE macros without id(0), Id(0 or ID(0). Valid values are 0, 16 or 32. (default 32) -dry-run No changes applied but output shows what would happen. - "trice insertSourceTreeIds -dry-run" will change nothing but show changes it would perform without the "-dry-run" switch. + "trice insert -dry-run" will change nothing but show changes it would perform without the "-dry-run" switch. This is a bool switch. It has no parameters. Its default value is false. If the switch is applied its value is true. You can also set it explicit: =false or =true. -i string Short for '-idlist'. @@ -444,7 +453,7 @@ sub-command 'i|insert': For updating til.json and inserting IDs into source file -src value Source dir or file, It has one parameter. Not usable in the form "-src *.c". This is a multi-flag switch. It can be used several times for directories and also for files. - Example: "trice insertSourceTreeIds -dry-run -v -src ./test/ -src pkg/src/trice.h" will scan all C|C++ header and + Example: "trice insert -dry-run -v -src ./test/ -src pkg/src/trice.h" will scan all C|C++ header and source code files inside directory ./test and scan also file trice.h inside pkg/src directory. Without the "-dry-run" switch it would create|extend a list file til.json in the current directory. (default "./") diff --git a/internal/emitter/emitter.go b/internal/emitter/emitter.go index d34703ba7..1c79b9e6e 100644 --- a/internal/emitter/emitter.go +++ b/internal/emitter/emitter.go @@ -84,7 +84,7 @@ func appendIfMissing(slice []string, i string) []string { func (i *channelArrayFlag) Set(value string) error { ss := strings.Split(value, ":") for _, s := range ss { - cv := channelVariants(s) + cv := tagVariants(s) for _, c := range cv { *i = appendIfMissing(*i, c) } diff --git a/internal/emitter/lineTransformerANSI.go b/internal/emitter/lineTransformerANSI.go index 3f1dd106c..31b14c884 100644 --- a/internal/emitter/lineTransformerANSI.go +++ b/internal/emitter/lineTransformerANSI.go @@ -97,64 +97,77 @@ func isLower(s string) bool { return true } -type colorChannel struct { - events int - channel []string - colorize func(string) string +type tag struct { + count int // count counts each occurance of the trice tag. + Names []string // name contains all usable names fo a specific tag. + colorize func(string) string // colorize is the function called for each tag. } -var colorChannels = []colorChannel{ +// Tags contains all usable trice Tags and their possible names. +var Tags = []tag{ // log level {0, []string{"Fatal", "fatal", "FATAL"}, colorizeFATAL}, - {0, []string{"Critical", "critical", "CRITICAL", "crit", "Crit", "CRIT"}, colorizeCRITICAL}, - {0, []string{"Emergency", "emergency", "EMERGENCY"}, colorizeEMERGENCY}, - {0, []string{"Error", "e", "err", "error", "E", "ERR", "ERROR"}, colorizeERROR}, - {0, []string{"Warning", "w", "wrn", "warning", "W", "WRN", "WARNING", "Warn", "warn", "WARN"}, colorizeWARNING}, + {0, []string{"crit", "Critical", "critical", "CRITICAL", "Crit", "CRIT"}, colorizeCRITICAL}, + {0, []string{"em", "Emergency", "emergency", "EMERGENCY"}, colorizeEMERGENCY}, + {0, []string{"e", "Error", "err", "error", "E", "ERR", "ERROR"}, colorizeERROR}, + {0, []string{"w", "wrn", "Warning", "warning", "W", "WRN", "WARNING", "Warn", "warn", "WARN"}, colorizeWARNING}, {0, []string{"att", "attention", "Attention", "ATT", "ATTENTION"}, colorizeATTENTION}, - {0, []string{"Info", "i", "inf", "info", "informal", "I", "INF", "INFO", "INFORMAL"}, colorizeINFO}, - {0, []string{"Debug", "d", "db", "dbg", "deb", "debug", "D", "DB", "DBG", "DEBUG"}, colorizeDEBUG}, - {0, []string{"Trace", "trace", "TRACE"}, colorizeTRACE}, + {0, []string{"i", "inf", "info", "Info", "informal", "I", "INF", "INFO", "INFORMAL"}, colorizeINFO}, + {0, []string{"d", "db", "Debug", "dbg", "deb", "debug", "D", "DB", "DBG", "DEBUG"}, colorizeDEBUG}, + {0, []string{"tr", "Trace", "trace", "TRACE"}, colorizeTRACE}, // user modes - {0, []string{"Timestamp", "tim", "time", "TIM", "TIME", "TIMESTAMP", "timestamp"}, colorizeTIME}, + {0, []string{"tim", "time", "TIM", "TIME", "TIMESTAMP", "timestamp", "Timestamp"}, colorizeTIME}, {0, []string{"m", "msg", "message", "M", "MSG", "MESSAGE", "OK"}, colorizeMESSAGE}, {0, []string{"r", "rx", "rd", "read", "rd_", "RD", "RD_", "READ"}, colorizeREAD}, {0, []string{"w", "tx", "wr", "write", "wr_", "WR", "WR_", "WRITE"}, colorizeWRITE}, - {0, []string{"receive", "rx", "RECEIVE", "Receive", "RX"}, colorizeRECEIVE}, - {0, []string{"transmit", "tx", "TRANSMIT", "Transmit", "TX"}, colorizeTRANSMIT}, + {0, []string{"rx", "receive", "RECEIVE", "Receive", "RX"}, colorizeRECEIVE}, + {0, []string{"tx", "transmit", "TRANSMIT", "Transmit", "TX"}, colorizeTRANSMIT}, {0, []string{"dia", "diag", "Diag", "DIA", "DIAG"}, colorizeDIAG}, {0, []string{"int", "isr", "ISR", "INT", "interrupt", "Interrupt", "INTERRUPT"}, colorizeINTERRUPT}, {0, []string{"s", "sig", "signal", "S", "SIG", "SIGNAL"}, colorizeSIGNAL}, {0, []string{"t", "tst", "test", "T", "TST", "TEST"}, colorizeTEST}, - {0, []string{"Default", "DEFAULT", "default"}, colorizeDEFAULT}, - {0, []string{"Notice", "NOTICE", "notice", "Note", "note", "NOTE"}, colorizeNOTICE}, + {0, []string{"def", "Default", "DEFAULT", "default"}, colorizeDEFAULT}, + {0, []string{"note", "Notice", "NOTICE", "notice", "Note", "NOTE"}, colorizeNOTICE}, {0, []string{"Alert", "alert", "ALERT"}, colorizeALERT}, {0, []string{"Assert", "assert", "ASSERT"}, colorizeASSERT}, - {0, []string{"Alarm", "alarm", "ALARM"}, colorizeALARM}, - {0, []string{"cycle", "CYCLE"}, colorizeCYCLE}, - {0, []string{"Verbose", "verbose", "VERBOSE"}, colorizeVERBOSE}, + {0, []string{"a", "Alarm", "alarm", "ALARM"}, colorizeALARM}, + {0, []string{"cy", "cycle", "CYCLE"}, colorizeCYCLE}, + {0, []string{"v", "Verbose", "verbose", "VERBOSE"}, colorizeVERBOSE}, } -// ColorChannelEvents returns count of occurred channel events. +func FindTagName(name string) (tagName string, err error) { + for _, t := range Tags { + for _, tn := range t.Names { + if tn == name { + tagName = t.Names[0] // take the first tag name as reference. + return + } + } + } + return "", fmt.Errorf("no tagName found for name %s", name) +} + +// TagEvents returns count of occurred channel events. // If ch is unknown, the returned value is -1. -func ColorChannelEvents(ch string) int { - for _, s := range colorChannels { - for _, c := range s.channel { +func TagEvents(ch string) int { + for _, s := range Tags { + for _, c := range s.Names { if c == ch { - return s.events + return s.count } } } return -1 } -// PrintColorChannelEvents shows the amount of occurred channel events. -func PrintColorChannelEvents(w io.Writer) { - for _, s := range colorChannels { - if s.events != 0 { - fmt.Fprintf(w, "%6d times: ", s.events) - for _, c := range s.channel { +// PrintTagEvents shows the amount of occurred channel events. +func PrintTagEvents(w io.Writer) { + for _, s := range Tags { + if s.count != 0 { + fmt.Fprintf(w, "%6d times: ", s.count) + for _, c := range s.Names { if ColorPalette != "off" && ColorPalette != "none" { c = s.colorize(c) } @@ -165,22 +178,22 @@ func PrintColorChannelEvents(w io.Writer) { } } -// channelVariants returns all variants of ch as string slice. +// tagVariants returns all variants of ch as string slice. // If ch is not inside ansiSel nil is returned. -func channelVariants(ch string) []string { - for _, s := range colorChannels { - for _, c := range s.channel { +func tagVariants(ch string) []string { + for _, s := range Tags { + for _, c := range s.Names { if c == ch { - return s.channel + return s.Names } } } return nil } -// isChannel returns true if ch is any ansiSel string. -func isChannel(ch string) bool { - cv := channelVariants(ch) +// isTag returns true if tag is any tag variant string. +func isTag(tag string) bool { + cv := tagVariants(tag) return cv != nil } @@ -203,10 +216,10 @@ func (p *lineTransformerANSI) colorize(s string) (r string, show bool) { if len(sc) < 2 { // no color separator (no log level) return r, true // do nothing, return unchanged string } - for i, cc := range colorChannels { - for _, c := range cc.channel { + for i, cc := range Tags { + for _, c := range cc.Names { if c == sc[0] { - colorChannels[i].events++ // count event + Tags[i].count++ // count event logLev = i } if c == LogLevel { @@ -223,14 +236,14 @@ func (p *lineTransformerANSI) colorize(s string) (r string, show bool) { if p.colorPalette == "off" { return r, true // do nothing (despite event counting) } - if isChannel(sc[0]) && isLower(sc[0]) { + if isTag(sc[0]) && isLower(sc[0]) { r = sc[1] // remove channel info } if p.colorPalette == "none" { return r, true } - for _, cs := range colorChannels { - for _, c := range cs.channel { + for _, cs := range Tags { + for _, c := range cs.Names { if c == sc[0] { return cs.colorize(r), true } diff --git a/internal/id/helper.go b/internal/id/helper.go index 2c9eacf28..3eb344151 100644 --- a/internal/id/helper.go +++ b/internal/id/helper.go @@ -22,6 +22,8 @@ import ( "github.com/spf13/afero" ) +var SkipAdditionalChecks bool + // CompactSrcs adds local dir to Srcs if Srcs is empty and reduces variable Scrs to the minimum to address all intended folders. func CompactSrcs() { if len(Srcs) == 0 { // Srcs is an array flag containing desired folders & files @@ -34,8 +36,6 @@ func CompactSrcs() { Srcs = slices.Compact(Srcs) } -var SkipAdditionalChecks bool - // fileExists returns true, if path exits. func fileExists(fSys *afero.Afero, path string) bool { if _, err := fSys.Stat(path); err == nil { diff --git a/internal/id/range_test.go b/internal/id/range_test.go new file mode 100644 index 000000000..5b00d64a9 --- /dev/null +++ b/internal/id/range_test.go @@ -0,0 +1,57 @@ +// Copyright 2024 Thomas.Hoehenleitner [at] seerose.net +// Use of this source code is governed by a license that can be found in the LICENSE file. + +package id_test + +import ( + "fmt" + "testing" + + "github.com/rokath/trice/internal/args" + . "github.com/rokath/trice/internal/id" + "github.com/tj/assert" +) + +// source tree management + +func TestRange0(t *testing.T) { + defer Setup(t)() + + // create src file + sFn := t.Name() + "file.c" + src := `trice("msg:Hi\n");trice("err:Alarm!\n");trice("msg:Lo\n");` + assert.Nil(t, FSys.WriteFile(sFn, []byte(src), 0777)) + + // action + assert.Nil(t, args.Handler(W, FSys, []string{"trice", "insert", "-IDMethod", "upward", "-src", sFn, "-til", FnJSON, "-li", LIFnJSON})) + + // check modified src file + expSrc := `trice(iD(1000), "msg:Hi\n");trice(iD(1001), "err:Alarm!\n");trice(iD(1002), "msg:Lo\n");` + + actSrc, e := FSys.ReadFile(sFn) + assert.Nil(t, e) + + assert.Equal(t, expSrc, string(actSrc)) +} + +func TestRange1(t *testing.T) { + defer Setup(t)() + + // create src file + sFn := t.Name() + "file.c" + src := `trice("msg:Hi\n"); ... trice("err:Alarm!\n"); ... trice("msg:Lo\n"); ... trice("dbg:foo\n");` + assert.Nil(t, FSys.WriteFile(sFn, []byte(src), 0777)) + + // action + assert.Nil(t, args.Handler(W, FSys, []string{"trice", "insert", "-IDRange", "e:100,109", "-IDRange", "dbg:200,209", "-IDMax=1005", "-IDMethod", "upward", "-src", sFn, "-til", FnJSON, "-li", LIFnJSON})) + + fmt.Println(IDData.IDSpace) + + // check modified src file + expSrc := `trice(iD(1000), "msg:Hi\n"); ... trice(iD(100), "err:Alarm!\n"); ... trice(iD(1001), "msg:Lo\n"); ... trice(iD(200), "dbg:foo\n");` + + actSrc, e := FSys.ReadFile(sFn) + assert.Nil(t, e) + + assert.Equal(t, expSrc, string(actSrc)) +} diff --git a/internal/id/switchIDs.go b/internal/id/switchIDs.go index ad58186e7..aa15da8f9 100644 --- a/internal/id/switchIDs.go +++ b/internal/id/switchIDs.go @@ -10,8 +10,10 @@ import ( "io" "log" "math/rand" + "strconv" "strings" + "github.com/rokath/trice/internal/emitter" "github.com/rokath/trice/pkg/ant" "github.com/rokath/trice/pkg/msg" "github.com/spf13/afero" @@ -19,28 +21,28 @@ import ( // idData holds the Id specific data. type idData struct { - idToTrice TriceIDLookUp // idToTrice is a trice ID lookup map and is generated from existing til.json file at the begin of SubCmdIdInsert. This map is only extended during SubCmdIdInsert and goes back into til.json afterwards. - triceToId triceFmtLookUp // triceToId is a trice fmt lookup map (reversed idToFmt for faster operation). Each fmt can have several trice IDs (slice). This map is only reduced during SubCmdIdInsert and goes _not_ back into til.json afterwards. - idToLocRef TriceIDLookUpLI // idToLocRef is the trice ID location information as reference generated from li.json (if exists) at the begin of SubCmdIdInsert and is not modified at all. At the end of SubCmdIdInsert a new li.json is generated from itemToId. - idToLocNew TriceIDLookUpLI // idToLocNew is the trice ID location information generated during insertTriceIDs. At the end of SubCmdIdInsert a new li.json is generated from idToLocRef + idToLocNew. - idInitialCount int // idInitialCount is the initial used ID count. - IDSpace []triceTagIDSpace // IDSpace contains the tag specific unused IDs. + idToTrice TriceIDLookUp // idToTrice is a trice ID lookup map and is generated from existing til.json file at the begin of SubCmdIdInsert. This map is only extended during SubCmdIdInsert and goes back into til.json afterwards. + triceToId triceFmtLookUp // triceToId is a trice fmt lookup map (reversed idToFmt for faster operation). Each fmt can have several trice IDs (slice). This map is only reduced during SubCmdIdInsert and goes _not_ back into til.json afterwards. + idToLocRef TriceIDLookUpLI // idToLocRef is the trice ID location information as reference generated from li.json (if exists) at the begin of SubCmdIdInsert and is not modified at all. At the end of SubCmdIdInsert a new li.json is generated from itemToId. + idToLocNew TriceIDLookUpLI // idToLocNew is the trice ID location information generated during insertTriceIDs. At the end of SubCmdIdInsert a new li.json is generated from idToLocRef + idToLocNew. + idInitialCount int // idInitialCount is the initial used ID count. + IDSpace []TagIDSpace // IDSpace contains the tag specific unused IDs. err error } -// triceTagIDSpace is a Trice tag specific ID space, specified with the -IDTag CLI switch. +// TagIDSpace is a Trice tag specific ID space, specified with the -IDTag CLI switch. // Example: "trice insert -IDTag err:10,99" specifies for the Trice tag "err" the ID space 10-99. -type triceTagIDSpace struct { - tag string // tag is the Trice message tag like "err" in TRice("err:foo");. - Min TriceID // Min is the smallest allowed trice tag specific ID. - Max TriceID // Max is the biggest allowed trice tag specific ID. - idSpace []TriceID // idSpace is the to tag assigned ID space. +type TagIDSpace struct { + tagName string // TagName is the Trice message tag like "err" in TRice("err:foo");. + min TriceID // Min is the smallest allowed trice tag specific ID. + max TriceID // Max is the biggest allowed trice tag specific ID. + iDSpace []TriceID // idSpace is the to tag assigned ID space. } // IDIsPartOfIDSpace returns true if ID is existent inside p.IDSpace. func (p *idData) IDIsPartOfIDSpace(id TriceID) bool { for _, tis := range p.IDSpace { - for _, iD := range tis.idSpace { + for _, iD := range tis.iDSpace { if iD == id { return true } @@ -54,14 +56,14 @@ func (p *idData) IDIsPartOfIDSpace(id TriceID) bool { // Example: When -IDMin=10, -IDMax=20 and id=99 found in source. func (p *idData) removeIDFromIDSpace(id TriceID) { for _, tis := range p.IDSpace { - for idx, iD := range tis.idSpace { + for idx, iD := range tis.iDSpace { if iD == id { if SearchMethod == "random" { // do not care about order inside tag.idSpace, so do it fast - fmt.Println("tag.idSpace=", tis.idSpace, "idx=", idx, "iD=", iD) - tis.idSpace[idx] = tis.idSpace[len(tis.idSpace)-1] // overwrite with last - tis.idSpace = tis.idSpace[:len(tis.idSpace)-1] // remove last + fmt.Println("tag.idSpace=", tis.iDSpace, "idx=", idx, "iD=", iD) + tis.iDSpace[idx] = tis.iDSpace[len(tis.iDSpace)-1] // overwrite with last + tis.iDSpace = tis.iDSpace[:len(tis.iDSpace)-1] // remove last } else { // keep order inside tag.idSpace, so do it costly - tis.idSpace = append(tis.idSpace[:idx], tis.idSpace[idx+1:]...) + tis.iDSpace = append(tis.iDSpace[:idx], tis.iDSpace[idx+1:]...) } } } @@ -69,7 +71,7 @@ func (p *idData) removeIDFromIDSpace(id TriceID) { } // triceTag returns the trice tag, if any, or an empty string. -func triceTag(t TriceFmt) string { // t.Strg contains the Trice tag information: string until the first colon matches a string in emitter.colorChannels. +func triceTag(t TriceFmt) string { // t.Strg contains the Trice tag information: string until the first colon matches a string in emitter.tags. before, _, ok := strings.Cut(t.Strg, ":") if !ok { return "" @@ -80,27 +82,28 @@ func triceTag(t TriceFmt) string { // t.Strg contains the Trice tag information: // newID returns a new, so far unused trice ID for usage. // The global variable SearchMethod controls the way a new ID is selected. func (p *idData) newID(t TriceFmt) (id TriceID) { - tag := triceTag(t) + name := triceTag(t) + tag, _ := emitter.FindTagName(name) common: for i := range p.IDSpace { // tis := p.IDSpace[i] <-- Why does this not work? todo - if tag != p.IDSpace[i].tag { + if tag != p.IDSpace[i].tagName { continue } if SearchMethod == "random" { - if len(p.IDSpace[i].idSpace) <= 0 { + if len(p.IDSpace[i].iDSpace) <= 0 { log.Fatal("Remaining IDSpace = is empty, check til.json. (You could re-create it or change -IDMin, -IDMax)") } - index := rand.Intn(len(p.IDSpace[i].idSpace)) - id = p.IDSpace[i].idSpace[index] // use random - p.IDSpace[i].idSpace[index] = p.IDSpace[i].idSpace[len(p.IDSpace[i].idSpace)-1] // overwrite with last - p.IDSpace[i].idSpace = p.IDSpace[i].idSpace[:len(p.IDSpace[i].idSpace)-1] // remove last + index := rand.Intn(len(p.IDSpace[i].iDSpace)) + id = p.IDSpace[i].iDSpace[index] // use random + p.IDSpace[i].iDSpace[index] = p.IDSpace[i].iDSpace[len(p.IDSpace[i].iDSpace)-1] // overwrite with last + p.IDSpace[i].iDSpace = p.IDSpace[i].iDSpace[:len(p.IDSpace[i].iDSpace)-1] // remove last } else if SearchMethod == "upward" { - id = p.IDSpace[i].idSpace[0] // use first - p.IDSpace[i].idSpace = p.IDSpace[i].idSpace[1:] // remove first + id = p.IDSpace[i].iDSpace[0] // use first + p.IDSpace[i].iDSpace = p.IDSpace[i].iDSpace[1:] // remove first } else { - id = p.IDSpace[i].idSpace[len(p.IDSpace[i].idSpace)-1] // use last - p.IDSpace[i].idSpace = p.IDSpace[i].idSpace[:len(p.IDSpace[i].idSpace)-1] // remove last + id = p.IDSpace[i].iDSpace[len(p.IDSpace[i].iDSpace)-1] // use last + p.IDSpace[i].iDSpace = p.IDSpace[i].iDSpace[:len(p.IDSpace[i].iDSpace)-1] // remove last } return } @@ -126,21 +129,21 @@ func (p *idData) PreProcessing(w io.Writer, fSys *afero.Afero) { p.GetIDStateFromJSONFiles(w, fSys) - var common triceTagIDSpace + var common TagIDSpace - common.tag = "" - common.Min = Min - common.Max = Max + common.tagName = "" + common.min = Min + common.max = Max p.IDSpace = append(p.IDSpace, common) for i, tis := range p.IDSpace { - for id := tis.Min; id <= tis.Max; id++ { + for id := tis.min; id <= tis.max; id++ { _, usedFmt := p.idToTrice[id] _, usedLoc := p.idToLocRef[id] if !usedFmt && !usedLoc { //tis.idSpace = append(tis.idSpace, id) //<- does not work here! todo: why? - p.IDSpace[i].idSpace = append(p.IDSpace[i].idSpace, id) + p.IDSpace[i].iDSpace = append(p.IDSpace[i].iDSpace, id) } else if Verbose { if usedFmt && !usedLoc { fmt.Fprintln(w, "ID", id, "used, but only inside til.json") @@ -154,7 +157,7 @@ func (p *idData) PreProcessing(w io.Writer, fSys *afero.Afero) { } } if Verbose { - fmt.Fprintln(w, "trice tag", tis.tag, "has", tis.Max-tis.Min+1, "IDs total space,", len(tis.idSpace), "IDs usable") + fmt.Fprintln(w, "trice tag", tis.tagName, "has", tis.max-tis.min+1, "IDs total space,", len(tis.iDSpace), "IDs usable") } } } @@ -198,3 +201,84 @@ func (p *idData) cmdSwitchTriceIDs(w io.Writer, fSys *afero.Afero, action ant.Pr p.postProcessing(w, fSys) return err } + +// EvaluateIDRangeStrings reads the -IDRange strings and fills the IDData.IDSpace accordingly. +// Each tag (like "err:") is allowed to occur only once, so a "e:" will fail after "err" was applied. +// IDRanges are not allowed to overlap. +func EvaluateIDRangeStrings() error { + var ( + tis *TagIDSpace + mi, ma int + err error + ) + // Interpret supplied IDRange string. + for _, x := range IDRange { + tis = new(TagIDSpace) + name, mima, found := strings.Cut(x, ":") + if !found { + continue + } + min, max, ok := strings.Cut(mima, ",") + if !ok { + goto returnErr + } + mi, err = strconv.Atoi(min) + if err != nil { + goto returnErr + } + tis.min = TriceID(mi) + ma, err = strconv.Atoi(max) + if err != nil { + goto returnErr + } + tis.max = TriceID(ma) + if mi > ma { + return fmt.Errorf("the with -IDRange applied ID range is inval Min(%d) > Max(%d)", mi, ma) + } + // Find tis.TagName. + for _, t := range emitter.Tags { + for _, tn := range t.Names { + if tn == name { + tis.tagName = t.Names[0] // take the first tag name as reference. + goto next + } + } + } + return fmt.Errorf("the with -IDRange applied name %s is unknown. Please check var Tags inside trice/internal/emitter/lineTransformerANSI.go for options", name) + next: + // Check for single name range assignment. + for _, ts := range IDData.IDSpace { + if ts.tagName == tis.tagName { + return fmt.Errorf("tagName %s has already an assigned ID range. Please check your command line", tis.tagName) + } + } + // Check for non overlapping ranges. + if !(Max < tis.min || tis.max < Min) { + return fmt.Errorf("overlapping ID ranges for %s (Min %d, Max %d) and default (Min %d, Max %d)", tis.tagName, tis.min, tis.max, Min, Max) + } + for _, ts := range IDData.IDSpace { + if ts.tagName == tis.tagName { + return fmt.Errorf("tagName %s has already an assigned ID range. Please check your command line", tis.tagName) + } + // ts.Min --- ts.Max --- tis.Min --- tis.Max <- non-overlapping: ts.Max < tis.Min + // tis.Min --- tis.Max --- ts.Min --- ts.Max <- non-overlapping: tis.Max < ts.Min + // ts.Min --- tis.Min --- tis.Max --- ts.Max <- !!! overlapping + // tis.Min --- ts.Min --- ts.Max --- tis.Max <- !!! overlapping + // tis.Min --- ts.Min --- tis.Max --- ts.Max <- !!! overlapping + // ts.Min --- tis.Min --- ts.Max --- tis.Max <- !!! overlapping + if !(ts.max < tis.min || tis.max < ts.min) { + return fmt.Errorf("overlapping ID ranges for %s (Min %d, Max %d) and %s (Min %d, Max %d)", tis.tagName, tis.min, tis.max, ts.tagName, ts.min, ts.max) + } + } + // Fill ID space. + for iD := tis.min; iD <= tis.max; iD++ { + tis.iDSpace = append(tis.iDSpace, iD) + } + IDData.IDSpace = append(IDData.IDSpace, *tis) + continue + + returnErr: + return fmt.Errorf("invalid syntax in %s - expecting \"TagName:number,number\"", x) + } + return nil +} diff --git a/internal/link/link.go b/internal/link/link.go index 8cd100c7b..caad3f217 100644 --- a/internal/link/link.go +++ b/internal/link/link.go @@ -18,7 +18,6 @@ import ( "time" "github.com/pkg/errors" - "github.com/rokath/trice/internal/id" "github.com/rokath/trice/pkg/msg" "github.com/spf13/afero" ) @@ -109,11 +108,11 @@ func NewDevice(w io.Writer, fSys *afero.Afero, port, arguments string) *Device { } } else { // get a temporary file name in a writable folder temp - dir := filepath.Dir(id.FnJSON) // the id list folder is assumed to be writable and readable + //dir := filepath.Dir(id.FnJSON) // the id list folder is assumed to be writable and readable // create temp folder if not exists - tempDir := filepath.Join(dir, "temp") - e := os.MkdirAll(tempDir, os.ModePerm) + tempDir := "./temp" // filepath.Join(dir, "temp") + e := fSys.MkdirAll(tempDir, os.ModePerm) msg.OnErr(e) // create a new file diff --git a/internal/translator/translator.go b/internal/translator/translator.go index 76d04903e..3c2ad73fd 100644 --- a/internal/translator/translator.go +++ b/internal/translator/translator.go @@ -91,7 +91,7 @@ func handleSIGTERM(w io.Writer, rc io.ReadCloser) { if Verbose { fmt.Fprintln(w, "####################################", sig, "####################################") } - emitter.PrintColorChannelEvents(w) + emitter.PrintTagEvents(w) msg.FatalOnErr(rc.Close()) os.Exit(0) // end case <-ticker.C: diff --git a/internal/trexDecoder/trexDecoder.go b/internal/trexDecoder/trexDecoder.go index e90004253..733fbff30 100644 --- a/internal/trexDecoder/trexDecoder.go +++ b/internal/trexDecoder/trexDecoder.go @@ -435,7 +435,7 @@ func (p *trexDec) Read(b []byte) (n int, err error) { } if cycle != 0xc0 { // with cycle counter and s.th. lost if cycle != p.cycle { // no cycle check for 0xc0 to avoid messages on every target reset and when no cycle counter is active - n += copy(b[n:], fmt.Sprint("CYCLE:\a", cycle, "!=", p.cycle, " # ", emitter.ColorChannelEvents("CYCLE")+1, " # ")) + n += copy(b[n:], fmt.Sprint("CYCLE:\a", cycle, "!=", p.cycle, " # ", emitter.TagEvents("CYCLE")+1, " # ")) p.cycle = cycle // adjust cycle } decoder.InitialCycle = false