• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokath / trice / 25204697298

28 Apr 2026 11:27PM UTC coverage: 91.023% (+3.0%) from 88.059%
25204697298

push

github

web-flow
Merge pull request #647 from rokath/wip

Improved README.md readability.

5354 of 5882 relevant lines covered (91.02%)

959.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.98
/internal/trexDecoder/trexDecoder.go
1
// SPDX-License-Identifier: MIT
2

3
// Package trexDecoder decodes framed TREX trice byte streams.
4
package trexDecoder
5

6
import (
7
        "bytes"
8
        "encoding/binary"
9
        "encoding/hex"
10
        "fmt"
11
        "io"
12
        "log"
13
        "math"
14
        "strings"
15
        "sync"
16

17
        cobs "github.com/rokath/cobs/go"
18
        "github.com/rokath/tcobs/v1"
19
        "github.com/rokath/trice/internal/decoder"
20
        "github.com/rokath/trice/internal/emitter"
21
        "github.com/rokath/trice/internal/id"
22
        "github.com/rokath/trice/pkg/cipher"
23
)
24

25
const (
26
        tyIdSize = 2 // tySize is what each trice message starts with: 2 bytes
27
        ncSize   = 2 // countSize is what each regular trice message contains after an optional target timestamp
28
        typeS0   = 1 // regular trice format without stamp     : 011iiiiiI NC ...
29
        typeS2   = 2 // regular trice format with 16-bit stamp : 101iiiiiI TT NC ...
30
        typeS4   = 3 // regular trice format with 32-bit stamp : 111iiiiiI TT TT NC ...
31
        typeX0   = 0 // regular trice format with 32-bit stamp : 001iiiiiI TT TT TT TT NC ...
32

33
        packageFramingNone = iota
34
        packageFramingCOBS
35
        packageFramingTCOBS   //v1
36
        packageFramingTCOBSv2 //v2
37
)
38

39
var (
40
        // Doubled16BitID enables acceptance of 16-bit IDs repeated twice in the header.
41
        Doubled16BitID bool
42

43
        // AddNewlineToEachTriceMessage appends a newline to each decoded Trice message when needed.
44
        AddNewlineToEachTriceMessage bool
45

46
        // SingleFraming demands that each received package contains at most one Trice message.
47
        SingleFraming bool
48

49
        // DisableCycleErrors suppresses cycle counter mismatch diagnostics.
50
        DisableCycleErrors bool
51
)
52

53
var specialCaseTriceTypes = map[string]struct{}{
54
        "TRICES": {}, "TRICEN": {}, "TRICEB": {}, "TRICEF": {},
55
        "TRICE8B": {}, "TRICE16B": {}, "TRICE32B": {}, "TRICE64B": {},
56
        "TRICE8F": {}, "TRICE16F": {}, "TRICE32F": {}, "TRICE64F": {},
57
        "TRICE_S": {}, "TRICE_N": {}, "TRICE_B": {}, "TRICE_F": {},
58
        "TRICE8_B": {}, "TRICE16_B": {}, "TRICE32_B": {}, "TRICE64_B": {},
59
        "TRICE8_F": {}, "TRICE16_F": {}, "TRICE32_F": {}, "TRICE64_F": {},
60
}
61

62
func init() {
12✔
63
        decoder.Register("TREX", New)
12✔
64
}
12✔
65

66
// trexDec is the decoder instance for TREX-encoded Trices.
67
type trexDec struct {
68
        decoder.DecoderData
69
        cycle          uint8  // cycle date: c0...bf
70
        pFmt           string // modified trice format string: %u -> %d
71
        u              []int  // 1: modified format string positions:  %u -> %d, 2: float (%f)
72
        packageFraming int
73
}
74

75
// New provides a TREX decoder instance.
76
//
77
// in is the input byte stream source.
78
func New(w io.Writer, lut id.TriceIDLookUp, m *sync.RWMutex, li id.TriceIDLookUpLI, in io.Reader, endian bool) decoder.Decoder {
21✔
79
        // Todo: rewrite using the TCOBS Reader. The provided in io.Reader provides a raw data stream.
21✔
80
        // https://github.com/rokath/tcobs/blob/master/TCOBSv1/read.go -> use NewDecoder ...
21✔
81

21✔
82
        p := &trexDec{
21✔
83
                DecoderData: decoder.NewDecoderData(decoder.Config{
21✔
84
                        Out:         w,
21✔
85
                        LUT:         lut,
21✔
86
                        LUTMutex:    m,
21✔
87
                        LI:          li,
21✔
88
                        In:          in,
21✔
89
                        Endian:      endian,
21✔
90
                        NeedBuffers: true,
21✔
91
                }),
21✔
92
                cycle: 0xc0, // start value
21✔
93
        }
21✔
94

21✔
95
        switch strings.ToLower(decoder.PackageFraming) {
21✔
96
        case "cobs":
8✔
97
                p.packageFraming = packageFramingCOBS
8✔
98
        case "tcobs", "tcobsv1":
3✔
99
                p.packageFraming = packageFramingTCOBS
3✔
100
        case "tcobsv2":
1✔
101
                p.packageFraming = packageFramingTCOBSv2
1✔
102
        case "none":
9✔
103
                p.packageFraming = packageFramingNone
9✔
104
        default:
×
105
                log.Fatal("Invalid framing switch:\a", decoder.PackageFraming)
×
106
        }
107
        return p
21✔
108
}
109

110
// nextData reads with an inner reader a raw byte stream.
111
//
112
// When fewer than 4 bytes are available, nextData returns without processing.
113
// That means the incoming data stream is exhausted and a next try should be started a bit later.
114
// Some arrived bytes are kept internally and concatenated with the following bytes in a next Read.
115
// Afterwards 0 or at least 4 bytes are inside p.B
116
func (p *trexDec) nextData() {
9✔
117
        m, err := p.In.Read(p.InnerBuffer)      // use p.InnerBuffer as destination read buffer
9✔
118
        p.B = append(p.B, p.InnerBuffer[:m]...) // merge with leftovers
9✔
119
        if err != nil && err != io.EOF {        // some serious error
9✔
120
                log.Fatal("ERROR:internal reader error\a", err) // exit
×
121
        }
×
122
}
123

124
// nextPackage reads with an inner reader a TCOBSv1 encoded byte stream.
125
//
126
// When no terminating 0 is found in the incoming bytes nextPackage returns without action.
127
// That means the incoming data stream is exhausted and a next try should be started a bit later.
128
// Some arrived bytes are kept internally and concatenated with the following bytes in a next Read.
129
// When a terminating 0 is found in the incoming bytes ReadFromCOBS decodes the COBS package
130
// and returns it in b and its len in n. If more data arrived after the first terminating 0,
131
// these are kept internally and concatenated with the following bytes in a next Read.
132
func (p *trexDec) nextPackage() {
632✔
133
        // Here p.IBuf contains none or available bytes, what can be several trice messages.
632✔
134
        // So first try to process p.IBuf.
632✔
135
        index := bytes.IndexByte(p.IBuf, 0) // find terminating 0
632✔
136
        if index == -1 {                    // p.IBuf has no complete COBS data, so try to read more input
1,258✔
137
                m, err := p.In.Read(p.InnerBuffer)            // use p.InnerBuffer as bytes read buffer
626✔
138
                p.IBuf = append(p.IBuf, p.InnerBuffer[:m]...) // merge with leftovers
626✔
139
                if err != nil && err != io.EOF {              // some serious error
626✔
140
                        log.Fatal("ERROR:internal reader error\a", err) // exit
×
141
                }
×
142
                index = bytes.IndexByte(p.IBuf, 0) // find terminating 0
626✔
143
                if index == -1 {                   // p.IBuf has no complete COBS data, so leave
1,241✔
144
                        // Even err could be io.EOF, some valid data possibly in p.iBUf.
615✔
145
                        // In case of file input (J-LINK usage) a plug off is not detectable here.
615✔
146
                        return // no terminating 0, nothing to do
615✔
147
                }
615✔
148
        }
149
        if decoder.TestTableMode {
17✔
150
                p.printTestTableLine(index + 1)
×
151
        }
×
152
        // here a complete COBS or TCOBS package exists
153
        if decoder.DebugOut { // Debug output
19✔
154
                fmt.Fprintf(p.W, "%s: ", decoder.PackageFraming)
2✔
155
                decoder.Dump(p.W, p.IBuf[:index+1])
2✔
156
        }
2✔
157

158
        frame := p.IBuf[:index]
17✔
159

17✔
160
        switch p.packageFraming {
17✔
161

162
        case packageFramingCOBS:
11✔
163
                p.B = p.B0                      // make([]byte, decoder.DefaultSize) // todo: avoid allocation
11✔
164
                n, e := cobs.Decode(p.B, frame) // if index is 0, an empty buffer is decoded
11✔
165
                p.IBuf = p.IBuf[index+1:]       // step forward (next package data in p.IBuf now, if any)
11✔
166
                if e != nil {
11✔
167
                        if decoder.Verbose {
×
168
                                fmt.Println("\ainconsistent COBS buffer!") // show also terminating 0
×
169
                        }
×
170
                }
171
                p.B = p.B[:n]
11✔
172

173
        case packageFramingTCOBS:
6✔
174
        repeat:
6✔
175
                p.B = p.B0                       // make([]byte, decoder.DefaultSize) // todo: avoid allocation
7✔
176
                n, e := tcobs.Decode(p.B, frame) // if index is 0, an empty buffer is decoded
7✔
177
                // from merging: p.IBuf = p.IBuf[index+1:]        // step forward (next package data in p.IBuf now, if any)
7✔
178
                if e != nil {
9✔
179
                        // remove 3 lines if they exist - see issue #403 for the reason.
2✔
180
                        s := strings.SplitN(strings.ReplaceAll(string(frame), "\r\n", "\n"), "\n", 4)
2✔
181
                        var bytesCount int
2✔
182
                        if len(s) >= 3 {
3✔
183
                                var newLines int
1✔
184
                                fmt.Println(s[0])
1✔
185
                                fmt.Println(s[1])
1✔
186
                                fmt.Println(s[2])
1✔
187
                                for _, b := range frame {
148✔
188
                                        frame = frame[1:]
147✔
189
                                        bytesCount++
147✔
190
                                        if b == 10 {
150✔
191
                                                newLines++
3✔
192
                                                if newLines == 3 {
4✔
193
                                                        break
1✔
194
                                                }
195
                                        }
196
                                        continue
146✔
197
                                }
198
                                index -= bytesCount
1✔
199
                                goto repeat
1✔
200
                        }
201
                        if decoder.Verbose {
1✔
202
                                fmt.Println(e, "\ainconsistent TCOBSv1 buffer:")
×
203
                                fmt.Println(e, hex.Dump(frame)) // show also terminating 0
×
204
                        }
×
205
                        e = nil
1✔
206
                        p.B = p.B[:0]
1✔
207
                        p.IBuf = p.IBuf[index+1:] // step forward (next package data in p.IBuf now, if any) // from merging:
1✔
208
                } else {
5✔
209
                        p.B = p.B[len(p.B)-n:]    // buffer is filled from the end
5✔
210
                        p.IBuf = p.IBuf[index+1:] // step forward (next package data in p.IBuf now, if any) // from merging:
5✔
211
                }
5✔
212
        default:
×
213
                log.Fatalln("unexpected execution path", p.packageFraming)
×
214
        }
215

216
        if decoder.DebugOut { // Debug output
19✔
217
                fmt.Fprint(p.W, "->TRICE: ")
2✔
218
                decoder.Dump(p.W, p.B)
2✔
219
        }
2✔
220

221
        if cipher.Password != "" { // encrypted
24✔
222
                cipher.Decrypt(p.B, p.B)
7✔
223
                if decoder.DebugOut { // Debug output
8✔
224
                        fmt.Fprint(p.W, "-> DEC:  ")
1✔
225
                        decoder.Dump(p.W, p.B)
1✔
226
                }
1✔
227
        }
228
}
229

230
// isZero reports whether all bytes in the slice are zero.
231
func isZero(bytes []byte) bool {
620✔
232
        b := byte(0)
620✔
233
        for _, s := range bytes {
630✔
234
                b |= s
10✔
235
        }
10✔
236
        return b == 0
620✔
237
}
238

239
// removeZeroHiByte discards one high-order padding zero byte from a candidate frame.
240
//
241
// The removed byte depends on configured endianness.
242
func (p *trexDec) removeZeroHiByte(s []byte) (r []byte) {
5✔
243
        // The package interpreter does not know the number of padding zeroes, so it needs to discard them one by one.
5✔
244
        // If they are not zero, this is an error.
5✔
245
        switch p.Endian {
5✔
246
        case decoder.BigEndian:
1✔
247
                // Big endian case: 00 00 AA AA C0 00 -> 00 AA AA C0 00 -> still typeX0 -> AA AA C0 00 -> ok next package
1✔
248
                if s[0] != 0 {
1✔
249
                        fmt.Println("unexpected case in line 273", string(s))
×
250
                }
×
251
                r = s[1:]
1✔
252
        case decoder.LittleEndian:
4✔
253
                // Little endian case: 00 00 AA AA C0 00 -> 00 AA AA C0 00 -> AA00 signals a valid Trice, but it is not! -> We need to remove the HI byte!
4✔
254
                if s[1] != 0 {
4✔
255
                        //log.Fatal("unexpected case", s)
×
256
                        // todo: This needs to be disabled for successfully running all test cases.
×
257
                        // BUT: deferred package framing NONE does not work
×
258
                }
×
259
                r = append(s[:1], s[2:]...)
4✔
260
        default:
×
261
                fmt.Println("unexpected case 927346193377", string(s))
×
262
        }
263
        return
5✔
264
}
265

266
// Read returns a single Trice conversion result or a single error message in b[:n].
267
// Read is the provided read method for TREX decoding and provides next string as byte slice.
268
//
269
// It uses inner reader p.In and internal id look-up table to fill b with a string.
270
// b is a slice of bytes with a len for the max expected string size.
271
// n is the count of read bytes inside b.
272
// Read returns usually one complete trice string or nothing but can return concatenated
273
// trice strings, each ending with a newline despite the last one, when messages added.
274
// Read does not process all internally read complete trice packages to be able later to
275
// separate Trices within one line to keep them separated for color processing.
276
// Therefore, Read needs to be called cyclically even after returning io.EOF to process internal data.
277
// When Read returns n=0, all processable complete trice packages are done,
278
// but the start of a following trice package can be already inside the internal buffer.
279
// In case of a not matching cycle, a warning message in trice format is prefixed.
280
// In case of invalid package data, error messages in trice format are returned and the package is dropped.
281
func (p *trexDec) Read(b []byte) (n int, err error) {
639✔
282
        if p.packageFraming == packageFramingNone {
647✔
283
                p.nextData() // returns all unprocessed data inside p.B
8✔
284
                p.B0 = p.B   // keep data for re-sync
8✔
285
        } else {
639✔
286
                if cipher.Password != "" && len(p.B) < 8 && isZero(p.B) {
1,249✔
287
                        p.B = p.B[:0] // Discard trailing zeroes. ATTENTION: incomplete trice messages containing many zeroes could be problematic here!
618✔
288
                }
618✔
289
                if len(p.B) == 1 { // last decoded package exhausted
632✔
290
                        if decoder.Verbose {
2✔
291
                                fmt.Println("Inconsistent data, discarding last single byte", p.B[0], "from:")
1✔
292
                                fmt.Println(hex.Dump(p.B))
1✔
293
                        }
1✔
294
                        p.B = p.B[:0]
1✔
295
                }
296
                if len(p.B) == 0 { // last decoded package exhausted
1,255✔
297
                        p.nextPackage() // returns one decoded package inside p.B
624✔
298
                }
624✔
299
        }
300
        packageSize := len(p.B)
639✔
301
        if packageSize < tyIdSize { // not enough data for a next package
1,255✔
302
                return
616✔
303
        }
616✔
304
        packed := p.B
23✔
305
        tyId := p.ReadU16(p.B)
23✔
306
        p.B = p.B[tyIdSize:]
23✔
307

23✔
308
        triceType := int(tyId >> decoder.IDBits) // most significant bit are the triceType
23✔
309
        triceID := id.TriceID(0x3FFF & tyId)     // 14 least significant bits are the ID
23✔
310
        decoder.LastTriceID = triceID            // used for showID
23✔
311
        decoder.RecordForStatistics(triceID)     // This is for the "trice log -stat" flag
23✔
312

23✔
313
        //typeX0Handler := "countedString"
23✔
314

23✔
315
        switch triceType {
23✔
316
        case typeS0: // no timestamp
10✔
317
                decoder.TargetTimestampSize = 0
10✔
318
        case typeS2: // 16-bit stamp
4✔
319
                decoder.TargetTimestampSize = 2
4✔
320
                if Doubled16BitID { // p.packageFraming == packageFramingNone || cipher.Password != "" {
6✔
321
                        if len(p.B) < 2 {
3✔
322
                                return // wait for more data
1✔
323
                        }
1✔
324

325
                        // Without encoding it needs to be done here.
326
                        // Also encrypted trice messages carry a double 16-bit ID.
327
                        p.B = p.B[tyIdSize:] // When target encoding is done, it removes the double 16-bit ID at the 16-bit timestamp trices.
1✔
328
                }
329
        case typeS4: // 32-bit stamp
6✔
330
                decoder.TargetTimestampSize = 4
6✔
331
        case typeX0: // extended trice type X0
3✔
332
                if p.packageFraming == packageFramingNone {
5✔
333
                        // typeX0 is not supported (yet)
2✔
334
                        if decoder.Verbose {
3✔
335
                                n += copy(b[n:], fmt.Sprintln("wrn:\aTo try to resync removing zero HI byte from:"))
1✔
336
                                n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B0)))
1✔
337
                        }
1✔
338
                        p.B = p.removeZeroHiByte(p.B0)
2✔
339
                        return
2✔
340
                }
341

342
                //  decoder.TargetTimestampSize = 0
343
                //  switch typeX0Handler {
344
                //  case "countedString":
345
                //          len := triceID
346
                //          //n += copy(b[n:], "vintage:")
347
                //          n += copy(b[n:], fmt.Sprintln(string(p.B[:len])))
348
                //          p.B = p.B[len:]
349
                //  default:
350
                //          n += copy(b[n:], fmt.Sprintln("ERROR:\aNo handler for triceType typeX0"))
351
                //  }
352
                //  return n, nil
353

354
                // We can reach here in target TRICE_MULTI_PACK_MODE, when a trice message is followed by several zeroes (up to 7 possible with encryption).
355
                p.B = p.removeZeroHiByte(packed)
1✔
356
        }
357

358
        if packageSize < tyIdSize+decoder.TargetTimestampSize+ncSize { // for non typeEX trices
20✔
359
                return // not enough data
×
360
        }
×
361

362
        // try to interpret
363
        switch triceType {
20✔
364
        case typeS0:
10✔
365
                decoder.TargetTimestamp = 0
10✔
366
        case typeS2: // 16-bit stamp
3✔
367
                decoder.TargetTimestamp = uint64(p.ReadU16(p.B))
3✔
368
        case typeS4: // 32-bit stamp
6✔
369
                decoder.TargetTimestamp = uint64(p.ReadU32(p.B))
6✔
370
        default: // typeX0
1✔
371
                //  switch typeX0Handler {
1✔
372
                //  case "countedString":
1✔
373
                //          len := triceID
1✔
374
                //          n += copy(b[n:], "USER:")
1✔
375
                //          n += copy(b[n:], fmt.Sprintln(string(p.B[:len])))
1✔
376
                //          p.B = p.B[len:]
1✔
377
                //  default:
1✔
378
                n += copy(b[n:], fmt.Sprintln("ERROR:\atriceType typeX0 not implemented (hint: IDBits value?)"))
1✔
379
                //  }
1✔
380
                return n, nil
1✔
381
        }
382
        //                decoder.TargetTimestampSize = 0
383
        //                switch typeX0Handler {
384
        //                case "countedString":
385
        //                        len := triceID
386
        //                        //n += copy(b[n:], "vintage:")
387
        //                        n += copy(b[n:], fmt.Sprintln(string(p.B[:len])))
388
        //                        p.B = p.B[len:]
389
        //                default:
390
        //                        n += copy(b[n:], fmt.Sprintln("ERROR:\aNo handler for triceType typeX0"))
391
        //                }
392
        //                return n, nil
393
        //
394
        //                //  if p.packageFraming == packageFramingNone {
395
        //                //          // typeX0 is not supported (yet)
396
        //                //          if decoder.Verbose {
397
        //                //                  n += copy(b[n:], fmt.Sprintln("wrn:\aTo try to resync removing zero HI byte from:"))
398
        //                //                  n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B0)))
399
        //                //          }
400
        //                //          p.B = p.removeZeroHiByte(p.B0)
401
        //                //          return
402
        //                //  }
403
        //                // We can reach here in target TRICE_MULTI_PACK_MODE, when a trice message is followed by several zeroes (up to 7 possible with encryption).
404
        //                // p.B = p.removeZeroHiByte(packed)
405
        //        }
406
        //
407
        //        if packageSize < tyIdSize+decoder.TargetTimestampSize+ncSize { // for non typeEX trices
408
        //                return // not enough data
409
        //        }
410
        //
411
        //        // try to interpret
412
        //        switch triceType {
413
        //        case typeS0:
414
        //                decoder.TargetTimestamp = 0
415
        //        case typeS2: // 16-bit stamp
416
        //                decoder.TargetTimestamp = uint64(p.ReadU16(p.B))
417
        //        case typeS4: // 32-bit stamp
418
        //                decoder.TargetTimestamp = uint64(p.ReadU32(p.B))
419
        //        default: // typeX0
420
        //                switch typeX0Handler {
421
        //                case "countedString":
422
        //                        len := triceID
423
        //                        n += copy(b[n:], "USER:")
424
        //                        n += copy(b[n:], fmt.Sprintln(string(p.B[:len])))
425
        //                        p.B = p.B[len:]
426
        //                default:
427
        //                        n += copy(b[n:], fmt.Sprintln("ERROR:\atriceType typeX0 not implemented (hint: IDBits value?)"))
428
        //                }
429
        //                return n, nil
430
        //        }
431

432
        p.B = p.B[decoder.TargetTimestampSize:]
19✔
433

19✔
434
        if len(p.B) < 2 {
20✔
435
                return // wait for more data
1✔
436
        }
1✔
437
        nc := p.ReadU16(p.B) // n = number of data bytes (without timestamp), most significant bit is the count encoding, c = cycle
18✔
438
        p.B = p.B[ncSize:]
18✔
439

18✔
440
        var cycle uint8
18✔
441
        if nc>>15 == 1 { // special case: more than data 127 bytes
19✔
442
                // C code: #define TRICE_LCNT(count) TRICE_PUT16( (0x8000 | (count)) );
1✔
443
                cycle = p.cycle                 // cycle is not transmitted, so set expected value
1✔
444
                p.ParamSpace = int(0x7FFF & nc) // 15 bit for data byte count excluding timestamp
1✔
445
        } else {
18✔
446
                // C code: #define TRICE_CNTC(count) TRICE_PUT16( ((count)<<8) | TRICE_CYCLE )
17✔
447
                cycle = uint8(nc)           // low byte is cycle
17✔
448
                p.ParamSpace = int(nc >> 8) // high byte is 7 bit number of bytes for data count excluding timestamp
17✔
449
        }
17✔
450

451
        p.TriceSize = tyIdSize + decoder.TargetTimestampSize + ncSize + p.ParamSpace
18✔
452
        if p.TriceSize > packageSize { //  '>' for multiple trices in one package (case TriceOutMultiPackMode), todo: discuss all possible variants
20✔
453
                if p.packageFraming == packageFramingNone {
3✔
454
                        if decoder.Verbose {
1✔
455
                                n += copy(b[n:], fmt.Sprintln("wrn:\adiscarding first byte", p.B0[0], "from:"))
×
456
                                n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B0)))
×
457
                        }
×
458
                        p.B0 = p.B0[1:] // discard first byte and try again
1✔
459
                        p.B = p.B0
1✔
460
                        return
1✔
461
                }
462
                if decoder.Verbose {
2✔
463
                        n += copy(b[n:], fmt.Sprintln("ERROR:\apackage size", packageSize, "is <", p.TriceSize, " - ignoring package:"))
1✔
464
                        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B)))
1✔
465
                        n += copy(b[n:], fmt.Sprintln("tyIdSize=", tyIdSize, "tsSize=", decoder.TargetTimestampSize, "ncSize=", ncSize, "ParamSpae=", p.ParamSpace))
1✔
466
                        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
467
                }
1✔
468
                p.B = p.B[len(p.B):] // discard buffer
1✔
469
        }
470
        if SingleFraming && p.TriceSize != packageSize {
18✔
471
                if decoder.Verbose {
2✔
472
                        n += copy(b[n:], fmt.Sprintln("ERROR:\asingle framed package size", packageSize, "is !=", p.TriceSize, " - ignoring package:"))
1✔
473
                        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B)))
1✔
474
                        n += copy(b[n:], fmt.Sprintln("tyIdSize=", tyIdSize, "tsSize=", decoder.TargetTimestampSize, "ncSize=", ncSize, "ParamSpae=", p.ParamSpace))
1✔
475
                        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
476
                }
1✔
477
                p.B = p.B[len(p.B):] // discard buffer
1✔
478
        }
479

480
        // cycle counter automatic & check
481
        if cycle == 0xc0 && p.cycle != 0xc0 && decoder.InitialCycle { // with cycle counter and seems to be a target reset
18✔
482
                n += copy(b[n:], fmt.Sprintln("warning:\a   Target Reset?   "))
1✔
483
                p.cycle = cycle + 1 // adjust cycle
1✔
484
                decoder.InitialCycle = false
1✔
485
        }
1✔
486
        if cycle == 0xc0 && p.cycle != 0xc0 && !decoder.InitialCycle { // with cycle counter and seems to be a target reset
19✔
487
                //n += copy(b[n:], fmt.Sprintln("info:   Target Reset?   ")) // todo: This line is ok with cycle counter but not without cycle counter
2✔
488
                p.cycle = cycle + 1 // adjust cycle
2✔
489
        }
2✔
490
        if cycle == 0xc0 && p.cycle == 0xc0 && decoder.InitialCycle { // with or without cycle counter and seems to be a target reset
20✔
491
                //n += copy(b[n:], fmt.Sprintln("warning:   Restart?   "))
3✔
492
                p.cycle = cycle + 1 // adjust cycle
3✔
493
                decoder.InitialCycle = false
3✔
494
        }
3✔
495
        if cycle == 0xc0 && p.cycle == 0xc0 && !decoder.InitialCycle { // with or without cycle counter and seems to be a normal case
24✔
496
                p.cycle = cycle + 1 // adjust cycle
7✔
497
        }
7✔
498
        if cycle != 0xc0 && !DisableCycleErrors { // with cycle counter and s.th. lost
22✔
499
                if cycle != p.cycle { // no cycle check for 0xc0 to avoid messages on every target reset and when no cycle counter is active
8✔
500
                        n += copy(b[n:], fmt.Sprintln("CYCLE_ERROR:\a", cycle, "!=", p.cycle, " (count=", emitter.TagEvents("CYCLE_ERROR")+1, ")"))
3✔
501
                        n += copy(b[n:], "                                         ") // len of location information plus stamp: 41 spaces - see NewlineIndent below - todo: make it generic
3✔
502
                        p.cycle = cycle                                               // adjust cycle
3✔
503
                }
3✔
504
                decoder.InitialCycle = false
5✔
505
                p.cycle++
5✔
506
        }
507

508
        var ok bool
17✔
509
        p.LutMutex.RLock()
17✔
510
        p.Trice, ok = p.Lut[triceID]
17✔
511
        if AddNewlineToEachTriceMessage {
17✔
512
                p.Trice.Strg += `\n` // this adds a newline to each single Trice message
×
513
        }
×
514
        p.LutMutex.RUnlock()
17✔
515
        if !ok {
19✔
516
                if p.packageFraming == packageFramingNone {
3✔
517
                        if decoder.Verbose {
1✔
518
                                n += copy(b[n:], fmt.Sprintln("wrn:\adiscarding first byte", p.B0[0], "from:"))
×
519
                                n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B0)))
×
520
                        }
×
521
                        p.B0 = p.B0[1:] // discard first byte and try again
1✔
522
                        p.B = p.B0
1✔
523
                } else {
1✔
524
                        n += copy(b[n:], fmt.Sprintln("WARNING:\aunknown ID ", triceID, "- ignoring trice ending with:"))
1✔
525
                        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B)))
1✔
526
                        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
527
                        p.B = p.B[:0] // discard all
1✔
528
                }
1✔
529
                return
2✔
530
        }
531

532
        n += p.sprintTrice(b[n:]) // use param info
15✔
533
        if len(p.B) < p.ParamSpace {
17✔
534
                if p.packageFraming == packageFramingNone {
3✔
535
                        if decoder.Verbose {
2✔
536
                                n += copy(b[n:], fmt.Sprintln("wrn:discarding first byte", p.B0[0], "from:"))
1✔
537
                                n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B0)))
1✔
538
                        }
1✔
539
                        p.B0 = p.B0[1:] // discard first byte and try again
1✔
540
                        p.B = p.B0
1✔
541
                } else {
1✔
542
                        n += copy(b[n:], fmt.Sprintln("ERROR:ignoring data garbage:"))
1✔
543
                        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B)))
1✔
544
                        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
545
                        p.B = p.B[:0] // discard all
1✔
546
                }
1✔
547
        } else {
13✔
548
                if p.packageFraming != packageFramingNone { // COBS | TCOBS are exact
24✔
549
                        p.B = p.B[p.ParamSpace:] // drop param info
11✔
550
                } else { // no package framing
13✔
551
                        padding := (p.ParamSpace + 3) & ^3
2✔
552
                        if padding <= len(p.B) {
3✔
553
                                p.B = p.B[padding:]
1✔
554
                        } else {
2✔
555
                                // n += copy(b[n:], fmt.Sprintln("wrn: cannot discard padding bytes", ))
1✔
556
                        }
1✔
557
                }
558
        }
559
        return
15✔
560
}
561

562
// sprintTrice writes a trice string or appropriate message into b and returns that len.
563
//
564
// p.Trice.Type is the received trice, in fact the name from til.json.
565
func (p *trexDec) sprintTrice(b []byte) (n int) {
21✔
566

21✔
567
        isSAlias := strings.HasPrefix(p.Trice.Strg, id.SAliasStrgPrefix) && strings.HasSuffix(p.Trice.Strg, id.SAliasStrgSuffix)
21✔
568
        if isSAlias { // A SAlias Strg is covered with id.SAliasStrgPrefix and id.SAliasStrgSuffix in til.json and it needs to be replaced with "%s" here.
22✔
569
                p.Trice.Strg = "%s" // See appropriate comment inside insertTriceIDs().
1✔
570
        }
1✔
571

572
        p.pFmt, p.u = decoder.UReplaceN(p.Trice.Strg)
21✔
573

21✔
574
        // remove Assert* from triceAssert* name if found
21✔
575
        before, _, found := strings.Cut(p.Trice.Type, "Assert")
21✔
576
        if found {
22✔
577
                p.Trice.Type = strings.TrimSpace(before)
1✔
578
        }
1✔
579

580
        triceType, err := id.ConstructFullTriceInfo(p.Trice.Type, len(p.u))
21✔
581

21✔
582
        if err != nil {
22✔
583
                n += copy(b[n:], fmt.Sprintln("err:ConstructFullTriceInfo failed with:", p.Trice.Type, len(p.B), "- ignoring package:"))
1✔
584
                return
1✔
585
        }
1✔
586
        ucTriceTypeReceived := strings.ToUpper(p.Trice.Type)   // examples: TRICE_S,   TRICE,   TRICE32,   TRICE16_2
20✔
587
        ucTriceTypeReconstructed := strings.ToUpper(triceType) // examples: TRICE32_S, TRICE0,  TRICE32_4, TRICE16_2
20✔
588
        for _, s := range cobsFunctionPtrList {                // walk through the list and try to find a match for execution
284✔
589
                if s.triceType == ucTriceTypeReconstructed || s.triceType == ucTriceTypeReceived { // match list entry "TRICE..."
283✔
590
                        if len(p.B) < p.ParamSpace {
22✔
591
                                n += copy(b[n:], fmt.Sprintln("err:len(p.B) =", len(p.B), "< p.ParamSpace = ", p.ParamSpace, "- ignoring package:"))
3✔
592
                                n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B[:len(p.B)])))
3✔
593
                                n += copy(b[n:], fmt.Sprintln(decoder.Hints))
3✔
594
                                return
3✔
595
                        }
3✔
596
                        if p.ParamSpace != (s.bitWidth>>3)*s.paramCount {
19✔
597
                                if !isSpecialCaseTriceType(s.triceType) {
4✔
598
                                        n += copy(b[n:], fmt.Sprintln("err:s.triceType =", s.triceType, "ParamSpace =", p.ParamSpace, "not matching with bitWidth ", s.bitWidth, "and paramCount", s.paramCount, "- ignoring package:"))
1✔
599
                                        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B[:len(p.B)])))
1✔
600
                                        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
601
                                        return
1✔
602
                                }
1✔
603
                        }
604
                        p.pFmt = applyMultilineIndent(p.pFmt)
15✔
605

15✔
606
                        n += s.triceFn(p, b, s.bitWidth, s.paramCount) // match found, call handler
15✔
607
                        return
15✔
608
                }
609
        }
610
        n += copy(b[n:], fmt.Sprintln("err:Unknown trice.Type:", p.Trice.Type, "and", triceType, "not matching - ignoring trice data:"))
1✔
611
        n += copy(b[n:], fmt.Sprintln(hex.Dump(p.B[:p.ParamSpace])))
1✔
612
        n += copy(b[n:], fmt.Sprintln(decoder.Hints))
1✔
613
        return
1✔
614
}
615

616
func isSpecialCaseTriceType(triceType string) bool {
5✔
617
        _, ok := specialCaseTriceTypes[strings.ToUpper(triceType)]
5✔
618
        return ok
5✔
619
}
5✔
620

621
func applyMultilineIndent(format string) string {
18✔
622
        segments := strings.Split(format, `\n`)
18✔
623
        if len(segments) < 3 {
34✔
624
                return format
16✔
625
        }
16✔
626
        if decoder.NewlineIndent == -1 {
4✔
627
                decoder.NewlineIndent = 12 + 1
2✔
628
                if !(id.LIFnJSON == "off" || id.LIFnJSON == "none") {
3✔
629
                        decoder.NewlineIndent += 28
1✔
630
                }
1✔
631
                if decoder.ShowID != "" {
3✔
632
                        decoder.NewlineIndent += 5
1✔
633
                }
1✔
634
        }
635
        skip := `\n` + strings.Repeat(" ", decoder.NewlineIndent)
2✔
636
        return strings.TrimRight(strings.Join(segments, skip), " ")
2✔
637
}
638

639
func splitChannelFormat(format string) (prefix string, itemFormat string, hadTrailingNewline bool) {
11✔
640
        before, after, found := strings.Cut(format, ":")
11✔
641
        if found {
20✔
642
                prefix = before + ":"
9✔
643
        } else {
11✔
644
                after = format
2✔
645
        }
2✔
646
        itemFormat = strings.TrimSuffix(after, `\n`)
11✔
647
        hadTrailingNewline = len(itemFormat) < len(after)
11✔
648
        return
11✔
649
}
650

651
// triceTypeFn is the type for cobsFunctionPtrList elements.
652
type triceTypeFn struct {
653
        triceType  string                                              // triceType describes if parameters, the parameter bit width or if the parameter is a string.
654
        triceFn    func(p *trexDec, b []byte, bitwidth, count int) int // triceFn performs the conversion to the output string.
655
        ParamSpace int                                                 // ParamSpace is the count of bytes allocated for the parameters.
656
        bitWidth   int                                                 // bitWidth is the individual parameter width.
657
        paramCount int                                                 // paramCount is the amount pf parameters for the format string, which must match the count of format specifiers.
658
}
659

660
// cobsFunctionPtrList is a function pointer list.
661
var cobsFunctionPtrList = [...]triceTypeFn{
662
        {"TRICE_0", (*trexDec).trice0, 0, 0, 0},
663
        {"TRICE8_1", (*trexDec).unSignedOrSignedOut, 1, 8, 1},
664
        {"TRICE8_2", (*trexDec).unSignedOrSignedOut, 2, 8, 2},
665
        {"TRICE8_3", (*trexDec).unSignedOrSignedOut, 3, 8, 3},
666
        {"TRICE8_4", (*trexDec).unSignedOrSignedOut, 4, 8, 4},
667
        {"TRICE8_5", (*trexDec).unSignedOrSignedOut, 5, 8, 5},
668
        {"TRICE8_6", (*trexDec).unSignedOrSignedOut, 6, 8, 6},
669
        {"TRICE8_7", (*trexDec).unSignedOrSignedOut, 7, 8, 7},
670
        {"TRICE8_8", (*trexDec).unSignedOrSignedOut, 8, 8, 8},
671
        {"TRICE8_9", (*trexDec).unSignedOrSignedOut, 9, 8, 9},
672
        {"TRICE8_10", (*trexDec).unSignedOrSignedOut, 10, 8, 10},
673
        {"TRICE8_11", (*trexDec).unSignedOrSignedOut, 11, 8, 11},
674
        {"TRICE8_12", (*trexDec).unSignedOrSignedOut, 12, 8, 12},
675
        {"TRICE16_1", (*trexDec).unSignedOrSignedOut, 2, 16, 1},
676
        {"TRICE16_2", (*trexDec).unSignedOrSignedOut, 4, 16, 2},
677
        {"TRICE16_3", (*trexDec).unSignedOrSignedOut, 6, 16, 3},
678
        {"TRICE16_4", (*trexDec).unSignedOrSignedOut, 8, 16, 4},
679
        {"TRICE16_5", (*trexDec).unSignedOrSignedOut, 10, 16, 5},
680
        {"TRICE16_6", (*trexDec).unSignedOrSignedOut, 12, 16, 6},
681
        {"TRICE16_7", (*trexDec).unSignedOrSignedOut, 14, 16, 7},
682
        {"TRICE16_8", (*trexDec).unSignedOrSignedOut, 16, 16, 8},
683
        {"TRICE16_9", (*trexDec).unSignedOrSignedOut, 18, 16, 9},
684
        {"TRICE16_10", (*trexDec).unSignedOrSignedOut, 20, 16, 10},
685
        {"TRICE16_11", (*trexDec).unSignedOrSignedOut, 22, 16, 11},
686
        {"TRICE16_12", (*trexDec).unSignedOrSignedOut, 24, 16, 12},
687
        {"TRICE32_1", (*trexDec).unSignedOrSignedOut, 4, 32, 1},
688
        {"TRICE32_2", (*trexDec).unSignedOrSignedOut, 8, 32, 2},
689
        {"TRICE32_3", (*trexDec).unSignedOrSignedOut, 12, 32, 3},
690
        {"TRICE32_4", (*trexDec).unSignedOrSignedOut, 16, 32, 4},
691
        {"TRICE32_5", (*trexDec).unSignedOrSignedOut, 20, 32, 5},
692
        {"TRICE32_6", (*trexDec).unSignedOrSignedOut, 24, 32, 6},
693
        {"TRICE32_7", (*trexDec).unSignedOrSignedOut, 28, 32, 7},
694
        {"TRICE32_8", (*trexDec).unSignedOrSignedOut, 32, 32, 8},
695
        {"TRICE32_9", (*trexDec).unSignedOrSignedOut, 36, 32, 9},
696
        {"TRICE32_10", (*trexDec).unSignedOrSignedOut, 40, 32, 10},
697
        {"TRICE32_11", (*trexDec).unSignedOrSignedOut, 44, 32, 11},
698
        {"TRICE32_12", (*trexDec).unSignedOrSignedOut, 48, 32, 12},
699
        {"TRICE64_1", (*trexDec).unSignedOrSignedOut, 8, 64, 1},
700
        {"TRICE64_2", (*trexDec).unSignedOrSignedOut, 16, 64, 2},
701
        {"TRICE64_3", (*trexDec).unSignedOrSignedOut, 24, 64, 3},
702
        {"TRICE64_4", (*trexDec).unSignedOrSignedOut, 32, 64, 4},
703
        {"TRICE64_5", (*trexDec).unSignedOrSignedOut, 40, 64, 5},
704
        {"TRICE64_6", (*trexDec).unSignedOrSignedOut, 48, 64, 6},
705
        {"TRICE64_7", (*trexDec).unSignedOrSignedOut, 56, 64, 7},
706
        {"TRICE64_8", (*trexDec).unSignedOrSignedOut, 64, 64, 8},
707
        {"TRICE64_9", (*trexDec).unSignedOrSignedOut, 72, 64, 9},
708
        {"TRICE64_10", (*trexDec).unSignedOrSignedOut, 80, 64, 10},
709
        {"TRICE64_11", (*trexDec).unSignedOrSignedOut, 88, 64, 11},
710
        {"TRICE64_12", (*trexDec).unSignedOrSignedOut, 96, 64, 12},
711

712
        {"TRICES", (*trexDec).triceS, -1, 0, 0},
713
        {"TRICEN", (*trexDec).triceN, -1, 0, 0},
714

715
        {"TRICE8F", (*trexDec).trice8F, -1, 0, 0},
716
        {"TRICE16F", (*trexDec).trice16F, -1, 0, 0},
717
        {"TRICE32F", (*trexDec).trice32F, -1, 0, 0},
718
        {"TRICE64F", (*trexDec).trice64F, -1, 0, 0},
719

720
        {"TRICE8B", (*trexDec).trice8B, -1, 0, 0},
721
        {"TRICE16B", (*trexDec).trice16B, -1, 0, 0},
722
        {"TRICE32B", (*trexDec).trice32B, -1, 0, 0},
723
        {"TRICE64B", (*trexDec).trice64B, -1, 0, 0},
724
}
725

726
// triceN converts dynamic strings.
727
func (p *trexDec) triceN(b []byte, _ int, _ int) int {
2✔
728
        s := string(p.B[:p.ParamSpace])
2✔
729
        // todo: evaluate p.Trice.Strg, use p.SLen and do whatever should be done
2✔
730
        return copy(b, fmt.Sprintf(p.Trice.Strg, s))
2✔
731
}
2✔
732

733
// triceS converts dynamic strings.
734
func (p *trexDec) triceS(b []byte, _ int, _ int) int {
2✔
735
        s := string(p.B[:p.ParamSpace])
2✔
736
        return copy(b, fmt.Sprintf(p.Trice.Strg, s))
2✔
737
}
2✔
738

739
// triceB converts dynamic buffers.
740
func (p *trexDec) trice8B(b []byte, _ int, _ int) (n int) {
3✔
741
        if decoder.DebugOut {
4✔
742
                fmt.Fprintln(p.W, string(p.B))
1✔
743
        }
1✔
744
        s := p.B[:p.ParamSpace]
3✔
745
        prefix, itemFormat, addLineBreak := splitChannelFormat(p.Trice.Strg)
3✔
746
        if prefix != "" {
5✔
747
                n += copy(b[n:], prefix)
2✔
748
        }
2✔
749

750
        for i := 0; i < len(s); i++ {
8✔
751
                n += copy(b[n:], fmt.Sprintf(itemFormat, s[i]))
5✔
752
        }
5✔
753
        if addLineBreak {
4✔
754
                n += copy(b[n:], fmt.Sprintln())
1✔
755
        }
1✔
756
        return
3✔
757
}
758

759
// trice16B converts dynamic buffers.
760
func (p *trexDec) trice16B(b []byte, _ int, _ int) (n int) {
2✔
761
        if decoder.DebugOut {
3✔
762
                fmt.Fprintln(p.W, string(p.B))
1✔
763
        }
1✔
764
        s := p.B[:p.ParamSpace]
2✔
765
        prefix, itemFormat, addLineBreak := splitChannelFormat(p.Trice.Strg)
2✔
766
        if prefix != "" {
4✔
767
                n += copy(b[n:], prefix)
2✔
768
        }
2✔
769

770
        for i := 0; i < len(s); i += 2 {
4✔
771
                n += copy(b[n:], fmt.Sprintf(itemFormat, binary.LittleEndian.Uint16(s[i:])))
2✔
772
        }
2✔
773
        if addLineBreak {
3✔
774
                n += copy(b[n:], fmt.Sprintln())
1✔
775
        }
1✔
776

777
        return
2✔
778
}
779

780
// trice32B converts dynamic buffers.
781
func (p *trexDec) trice32B(b []byte, _ int, _ int) (n int) {
2✔
782
        if decoder.DebugOut {
3✔
783
                fmt.Fprintln(p.W, string(p.B))
1✔
784
        }
1✔
785
        s := p.B[:p.ParamSpace]
2✔
786
        prefix, itemFormat, addLineBreak := splitChannelFormat(p.Trice.Strg)
2✔
787
        if prefix != "" {
4✔
788
                n += copy(b[n:], prefix)
2✔
789
        }
2✔
790

791
        for i := 0; i < len(s); i += 4 {
4✔
792
                n += copy(b[n:], fmt.Sprintf(itemFormat, binary.LittleEndian.Uint32(s[i:])))
2✔
793
        }
2✔
794
        if addLineBreak {
3✔
795
                n += copy(b[n:], fmt.Sprintln())
1✔
796
        }
1✔
797
        return
2✔
798
}
799

800
// trice64B converts dynamic buffers.
801
func (p *trexDec) trice64B(b []byte, _ int, _ int) (n int) {
2✔
802
        if decoder.DebugOut {
3✔
803
                fmt.Fprintln(p.W, string(p.B))
1✔
804
        }
1✔
805
        s := p.B[:p.ParamSpace]
2✔
806
        prefix, itemFormat, addLineBreak := splitChannelFormat(p.Trice.Strg)
2✔
807
        if prefix != "" {
4✔
808
                n += copy(b[n:], prefix)
2✔
809
        }
2✔
810

811
        for i := 0; i < len(s); i += 8 {
4✔
812
                n += copy(b[n:], fmt.Sprintf(itemFormat, binary.LittleEndian.Uint64(s[i:])))
2✔
813
        }
2✔
814
        if addLineBreak {
3✔
815
                n += copy(b[n:], fmt.Sprintln())
1✔
816
        }
1✔
817
        return
2✔
818
}
819

820
// trice8F display function call with 8-bit parameters.
821
func (p *trexDec) trice8F(b []byte, _ int, _ int) (n int) {
2✔
822
        if decoder.DebugOut {
3✔
823
                fmt.Fprintln(p.W, string(p.B))
1✔
824
        }
1✔
825
        s := p.B[:p.ParamSpace]
2✔
826
        n += copy(b[n:], fmt.Sprint(p.Trice.Strg))
2✔
827
        for i := 0; i < len(s); i++ {
5✔
828
                n += copy(b[n:], fmt.Sprintf("(%02x)", s[i]))
3✔
829
        }
3✔
830
        n += copy(b[n:], fmt.Sprintln())
2✔
831
        return
2✔
832
}
833

834
// trice16F display function call with 16-bit parameters.
835
func (p *trexDec) trice16F(b []byte, _ int, _ int) (n int) {
2✔
836
        if decoder.DebugOut {
3✔
837
                fmt.Fprintln(p.W, string(p.B))
1✔
838
        }
1✔
839
        s := p.B[:p.ParamSpace]
2✔
840
        n += copy(b[n:], fmt.Sprint(p.Trice.Strg))
2✔
841
        for i := 0; i < len(s); i += 2 {
4✔
842
                n += copy(b[n:], fmt.Sprintf("(%04x)", binary.LittleEndian.Uint16(s[i:])))
2✔
843
        }
2✔
844
        n += copy(b[n:], fmt.Sprintln())
2✔
845
        return
2✔
846
}
847

848
// trice32F display function call with 32-bit parameters.
849
func (p *trexDec) trice32F(b []byte, _ int, _ int) (n int) {
2✔
850
        if decoder.DebugOut {
3✔
851
                fmt.Fprintln(p.W, string(p.B))
1✔
852
        }
1✔
853
        s := p.B[:p.ParamSpace]
2✔
854
        n += copy(b[n:], fmt.Sprint(p.Trice.Strg))
2✔
855
        for i := 0; i < len(s); i += 4 {
4✔
856
                n += copy(b[n:], fmt.Sprintf("(%08x)", binary.LittleEndian.Uint32(s[i:])))
2✔
857
        }
2✔
858
        n += copy(b[n:], fmt.Sprintln())
2✔
859
        return
2✔
860
}
861

862
// trice64F display function call with 64-bit parameters.
863
func (p *trexDec) trice64F(b []byte, _ int, _ int) (n int) {
2✔
864
        if decoder.DebugOut {
3✔
865
                fmt.Fprintln(p.W, string(p.B))
1✔
866
        }
1✔
867
        s := p.B[:p.ParamSpace]
2✔
868
        n += copy(b[n:], fmt.Sprint(p.Trice.Strg))
2✔
869
        for i := 0; i < len(s); i += 8 {
4✔
870
                n += copy(b[n:], fmt.Sprintf("(%016x)", binary.LittleEndian.Uint64(s[i:])))
2✔
871
        }
2✔
872
        n += copy(b[n:], fmt.Sprintln())
2✔
873
        return
2✔
874
}
875

876
// trice0 prints the trice format string.
877
func (p *trexDec) trice0(b []byte, _ int, _ int) int {
7✔
878
        return copy(b, fmt.Sprint(p.pFmt))
7✔
879
}
7✔
880

881
// unSignedOrSignedOut prints p.B according to the format string.
882
func (p *trexDec) unSignedOrSignedOut(b []byte, bitwidth, count int) int {
17✔
883
        if len(p.u) != count {
18✔
884
                return copy(b, fmt.Sprintln("ERROR: Invalid format specifier count inside", p.Trice.Type, p.Trice.Strg))
1✔
885
        }
1✔
886
        v := make([]interface{}, 32768) // theoretical 2^15 bytes could arrive
16✔
887
        switch bitwidth {
16✔
888
        case 8:
6✔
889
                for i, f := range p.u {
15✔
890
                        switch f {
9✔
891
                        case decoder.UnsignedFormatSpecifier, decoder.PointerFormatSpecifier: // see comment inside decoder.UReplaceN
2✔
892
                                v[i] = p.B[i]
2✔
893
                        case decoder.SignedFormatSpecifier:
5✔
894
                                v[i] = int8(p.B[i])
5✔
895
                        case decoder.BooleanFormatSpecifier:
1✔
896
                                v[i] = p.B[i] != 0
1✔
897
                        default:
1✔
898
                                return copy(b, fmt.Sprintln("ERROR: Invalid format specifier (float?) inside", p.Trice.Type, p.Trice.Strg))
1✔
899
                        }
900
                }
901
        case 16:
3✔
902
                for i, f := range p.u {
7✔
903
                        n := p.ReadU16(p.B[2*i:])
4✔
904
                        switch f {
4✔
905
                        case decoder.UnsignedFormatSpecifier, decoder.PointerFormatSpecifier: // see comment inside decoder.UReplaceN
×
906
                                v[i] = n
×
907
                        case decoder.SignedFormatSpecifier:
2✔
908
                                v[i] = int16(n)
2✔
909
                        case decoder.BooleanFormatSpecifier:
1✔
910
                                v[i] = n != 0
1✔
911
                        default:
1✔
912
                                return copy(b, fmt.Sprintln("ERROR: Invalid format specifier (float?) inside", p.Trice.Type, p.Trice.Strg))
1✔
913
                        }
914
                }
915
        case 32:
5✔
916
                for i, f := range p.u {
14✔
917
                        n := p.ReadU32(p.B[4*i:])
9✔
918
                        switch f {
9✔
919
                        case decoder.UnsignedFormatSpecifier, decoder.PointerFormatSpecifier: // see comment inside decoder.UReplaceN
×
920
                                v[i] = n
×
921
                        case decoder.SignedFormatSpecifier:
6✔
922
                                v[i] = int32(n)
6✔
923
                        case decoder.FloatFormatSpecifier:
1✔
924
                                v[i] = math.Float32frombits(n)
1✔
925
                        case decoder.BooleanFormatSpecifier:
1✔
926
                                v[i] = n != 0
1✔
927
                        default:
1✔
928
                                return copy(b, fmt.Sprintln("ERROR: Invalid format specifier inside", p.Trice.Type, p.Trice.Strg))
1✔
929
                        }
930
                }
931
        case 64:
2✔
932
                for i, f := range p.u {
5✔
933
                        n := p.ReadU64(p.B[8*i:])
3✔
934
                        switch f {
3✔
935
                        case decoder.UnsignedFormatSpecifier, decoder.PointerFormatSpecifier: // see comment inside decoder.UReplaceN
×
936
                                v[i] = n
×
937
                        case decoder.SignedFormatSpecifier:
1✔
938
                                v[i] = int64(n)
1✔
939
                        case decoder.FloatFormatSpecifier:
1✔
940
                                v[i] = math.Float64frombits(n)
1✔
941
                        case decoder.BooleanFormatSpecifier:
1✔
942
                                v[i] = n != 0
1✔
943
                        default:
×
944
                                return copy(b, fmt.Sprintln("ERROR: Invalid format specifier inside", p.Trice.Type, p.Trice.Strg))
×
945
                        }
946
                }
947
        }
948
        return copy(b, fmt.Sprintf(p.pFmt, v[:len(p.u)]...))
13✔
949
}
950

951
var testTableVirgin = true
952

953
// printTestTableLine is used to generate testdata
954
func (p *trexDec) printTestTableLine(n int) {
1✔
955
        if emitter.NextLine || testTableVirgin {
2✔
956
                emitter.NextLine = false
1✔
957
                testTableVirgin = false
1✔
958
                fmt.Printf("{ []byte{ ")
1✔
959
        }
1✔
960
        for _, b := range p.IBuf[0:n] { // just to see trice bytes per trice
3✔
961
                fmt.Printf("%3d,", b)
2✔
962
        }
2✔
963
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc