Trice user guide
_(Read this)
SORRY: This document is long and not 100% consistent. Hints or pull requests are welcome.
Table of Contents
-
- [*Trice* user guide](#trice-user-guide)
- [1. Project structure](#1-project-structure)
- [2. Get started](#2-get-started)
- [2.1. Get it](#21-get-it)
- [2.2. Install It](#22-install-it)
- [2.3. Try it](#23-try-it)
- [2.4. Use It](#24-use-it)
- [2.5. Port it](#25-port-it)
- [2.5.1. Target Macros](#251-target-macros)
- [2.5.2. Target Trice Stamps](#252-target-trice-stamps)
- [2.5.3. Trice Checks](#253-trice-checks)
- [2.5.4. Communication Ports](#254-communication-ports)
- [2.5.5. Target Code Overview](#255-target-code-overview)
- [2.5.6. User Code Adaption](#256-user-code-adaption)
- [2.5.7. Limitations](#257-limitations)
- [2.5.8. Trice (Time) Stamps](#258-trice-time-stamps)
- [2.5.9. Trice Parameter Bit Widths](#259-trice-parameter-bit-widths)
- [2.6. Avoid it](#26-avoid-it)
- [2.6.1. Parser Limitation](#261-parser-limitation)
- [2.6.2. Trice macros in header files](#262-trice-macros-in-header-files)
- [2.6.3. Trice macros inside other macros](#263-trice-macros-inside-other-macros)
- [3. Build `trice` tool from Go sources (you can skip that)](#3-build-trice-tool-from-go-sources-you-can-skip-that)
- [4. Embedded system code configuration](#4--embedded-system-code-configuration)
- [5. `trice` tool in logging action](#5-trice-tool-in-logging-action)
- [6. Encryption](#6-encryption)
- [7. CLI Options for `trice` tool](#7-cli-options-for-trice-tool)
- [8. *Trice* command line examples](#8-trice-command-line-examples)
- [8.1. Common information](#81-common-information)
- [8.2. Further examples](#82-further-examples)
- [8.2.1. Automated pre-build insert command example](#821-automated-pre-build-insert-command-example)
- [8.2.2. Some Log examples](#822-some-log-examples)
- [8.2.3. Logging over a display server](#823-logging-over-a-display-server)
- [8.2.4. Logfile output](#824-logfile-output)
- [8.2.5. Binary Logfile](#825-binary-logfile)
- [8.2.6. TCP output](#826-tcp-output)
- [8.2.7. TCP input](#827-tcp-input)
- [8.2.8. Stimulate target with a user command over UART](#828-stimulate-target-with-a-user-command-over-uart)
- [8.2.9. Explpore and modify channels and their colors](#829-explpore-and-modify-channels-and-their-colors)
- [8.2.10. Location Information](#8210-location-information)
- [9. Limitations](#9-limitations)
- [9.1. Permanent Limitations](#91-permanent-limitations)
- [9.1.1. Limitation TRICE in TRICE not possible](#911-limitation-trice-in-trice-not-possible)
- [9.2. Current Limitations](#92-current-limitations)
- [9.2.1. String Concatenation Within TRICE Macros Not Possible](#921-string-concatenation-within-trice-macros-not-possible)
- [9.2.2. Limited Trice Parser Capabilities](#922-limited-trice-parser-capabilities)
- [10. Additional hints](#10-additional-hints)
- [10.1. Pre-built executables are available](#101-pre-built-executables-are-available)
- [10.2. Configuration file `triceConfig.h`](#102-configuration-file-triceconfigh)
- [10.3. Setting up the very first connection](#103-setting-up-the-very-first-connection)
- [10.4. Avoid buffer overruns](#104-avoid-buffer-overruns)
- [10.5. Buffer Macros](#105-buffer-macros)
- [10.6. Logfile viewing](#106-logfile-viewing)
- [10.7. Using the `trice` tool with 3rd party tools](#107-using-the-trice-tool-with-3rd-party-tools)
- [10.8. Several targets at the same time](#108-several-targets-at-the-same-time)
- [10.9. Executing `go test -race -count 100 ./...`](#109-executing-go-test--race--count-100-)
- [10.10. Direct TRICE Out (TRICE\_MODE TRICE\_STACK\_BUFFER) could cause stack overflow with -o0 optimization](#1010-direct-trice-out-trice_mode-trice_stack_buffer-could-cause-stack-overflow-with--o0-optimization)
- [10.11. Cycle Counter](#1011-cycle-counter)
- [11. Switching *Trice* ON and OFF](#11-switching-trice-on-and-off)
- [11.1. Target side compile-time *Trice* On-Off](#111-target-side-compile-time--trice-on-off)
- [11.2. Host side *Trice* On-Off](#112-host-side-trice-on-off)
- [12. Framing](#12-framing)
- [13. Optional XTEA Encryption](#13-optional-xtea-encryption)
- [14. Endianness](#14-endianness)
- [15. `TRICE` (Time)Stamps](#15-trice-timestamps)
- [16. Binary Encoding](#16-binary-encoding)
- [16.1. Symbols](#161-symbols)
- [16.2. Package Format](#162-package-format)
- [17. Trice Decoding](#17-trice-decoding)
- [17.1. *Trice* ID list `til.json`](#171-trice-id-list-tiljson)
- [17.2. *Trice* location information file `li.json`](#172-trice-location-information-file-lijson)
- [18. *Trice* ID Numbers](#18-trice-id-numbers)
- [18.1. ID number selection](#181-id-number-selection)
- [18.2. ID number usage and stability](#182-id-number-usage-and-stability)
- [18.3. *Trice* ID 0](#183-trice-id-0)
- [19. Trice ID management](#19-trice-id-management)
- [19.1. *Trices* inside source code](#191-trices-inside-source-code)
- [19.1.1. *Trices* in source code comments](#1911-trices-in-source-code-comments)
- [19.1.2. Different IDs for same *Trices*](#1912-different-ids-for-same-trices)
- [19.1.3. Same IDs for different *Trices*](#1913-same-ids-for-different-trices)
- [20. ID reference list **til.json**](#20-id-reference-list-tiljson)
- [20.1. **til.json** Version control](#201-tiljson-version-control)
- [20.2. Long Time Availability](#202-long-time-availability)
- [21. The `trice insert` Algorithm](#21-the-trice-insert-algorithm)
- [21.1. Starting Conditions](#211-starting-conditions)
- [21.2. Aims](#212-aims)
- [21.3. Method](#213-method)
- [21.3.1. `insert` Initialization](#2131-insert-initialization)
- [21.4. User Code Patching (`trice insert`)](#214-user-code-patching-trice-insert)
- [21.5. User Code Patching Examples](#215-user-code-patching-examples)
- [21.6. User Code Un-Patching](#216-user-code-un-patching)
- [21.7. ID Usage Options](#217-id-usage-options)
- [21.8. General ID Management Information](#218-general-id-management-information)
- [21.9. Option 1: Let the inserted Trice ID be a Part of the User Code](#219-option-1-let-the-inserted-trice-id-be-a-part-of-the-user-code)
- [21.10. Option 2: Cleaning in a Post-build process](#2110-option-2-cleaning-in-a-post-build-process)
- [21.11. Option 3: Cleaning on Repository Check-In](#2111-option-3-cleaning-on-repository-check-in)
- [22. Changelog](#22-changelog)
1. Project structure
2. Get started
2.1. Get it
- Download latest release assets for your system: Compressed source code and binaries.
- OR Get the repo:
- OR use the button
2.2. Install It
- Place the extracted trice binary somewhere in your PATH.
- Copy the src folder into your project and add all files.
- Copy a triceConfig.h from a subfolder in the examples or test folder and optionally adapt it. See file triceDefaultConfig.h for help.
- Inside the triceCnfig.h file cou can control, if Trice works in direct or deferred mode or both parallel.
2.3. Try it
- Create a file
tryTrice.c
and write in it:
#include "trice.h"
int tryIt( void ){
trice( "Hello! ππ\a\n" ); // A message with sound and without target timestamp.
}
You can also edit any of your existing project files accordingly. Just replace any printf
with trice
. (Handle float or double numbers and runtime-generated stings, according to TriceVsPrintfSimilaritiesAndDifferences.md. The file _test/testdata/triceCheck.c shows many usage examples.
The uppercase TRICE
macros are inlining the complete Trice code and the lowercase trice
macros are function calls, so most probably you want use trice
to keep the overall code size smaller.
- Create 2 empty files
til.json
andli.json
in your project root. - Run
trice insert
and the trice code line changes totrice( iD(1234), "Hello! ππ\a\n" );
. - The 2 JSON files are now filled with information.
- Run
trice clean
and the trice code line changes back totrice( "Hello! ππ\a\n" );
.
You can use trice insert
as pre- and trice clean
as post-compile step, to not spoil your source code with IDs.
The optional Trice cache technique avoids un-edited file changes at all, what means no Trice releated build speed disadvantages.
See TriceCacheSpec.md for more details and examples/G1B1_inst/build.sh as example.
- Or, use
trice insert
in a post-checkout andtrice clean
in a pre-check-in script to keep just the repository clean of Trice IDs. Using onlytrice insert
as pre-compile step is possible too, especially when the code is used just in a single project and you wish to have it as compiled. - When using Trice in libraries for several projects, it may make sense to check-in the libraries with IDs and to use a dedicated ID space for them. See ../_test/testdata/triceCheck.c as an example - especially when building several projects parallel like shown in the examples folder.
A quick setup is possible when using RTT as output channel. Otherwise you need to setup a serial port for Trice data transmission. Other output paths possible too using the auxilary interface.
2.4. Use It
- In a console, like git bash, type
trice help -all
. You should see the complete trice tool CLI documentation.- DonΒ΄t worry, most of it you will never need.
- There are only 2 important commands:
trice insert
andtrice log
. Call them with the right CLI switches.trice help -insert
andtrice help -log
show partial help.-
Examples:
CLI command Description touch ./til.json
Create an empty til.json file
. This is needed only the very first time.trice i -src . -src ../myLib
Insert IDs to the current and your ../myLib
folder. This will read|extend|modify./til.json
and use & create the./li.json
file.β¦ Compile your project trice c -src . -src ../myLib
Optionally restore the current and your ../myLib
folder. This will read|extend|modify./til.json
and use & create the./li.json
file.trice l -p com1 -baud 921600 -lf my/path/auto
Start Logging over UART and create automatically a new log file in my/path/
.cat filename.log
View a recorded log file. trice l -p JLINK -args "..."
Start Logging over RTT. Binary log files are collected in ./temp
.trice l -p FILEBUFFER -args logfile.bin
Play a recorded binary log file. - It is recommended to add
trice insert ...
as pre-compile step into the tool chain. - Hint: It is possible to add
trice clean ...
as a post-compile step, so that you can check in your project sources without IDs. That is supported in v0.61.0 and later. This allows to use library sources with trices in different projects and the source code is not spoiled with IDs.
- The command
trice
does not make any assumptions about the target processor - 8-bit to 64-bit, supports little and big endianness. - The command
trice
is compiler agnostic - it should work with any compiler. - The vsCode editor is free downloadable and free usable, like shown in the
examples/F030R8_inst
project.- Even if you do not have such hardware, you can compile the
examples/F030R8_inst
project just to get started. - When adding or modifying
trice
macros inside examples/F030R8_inst/Core/Src/main.c and recompiling you should see automatically changed ID numbers inside the code.
- Even if you do not have such hardware, you can compile the
- The examples and test subfolders contains several vsCode Makefile projects and they are also usable as starting points for your configuration.
- You can use Trice calls also inside header files but when running
trice insert
as pre- andtrice clean
as post-compile step, all files including these headers will be re-compiled every time, what may be too time consuming. Enable the Trice cache then. See TriceCacheSpec.md for more information.
2.5. Port it
Trice should be usable on any MCU with any compiler. On ARM MCUs the easiest way is to use SEGGER J-Link with RTT as output. Setting up UART transmission as alternative or additionally is also no big deal.
Compare folders of one of these folder groups:
Without Instrumentation | With Trice Instrumentation |
---|---|
./examples/F030R8_gen |
./examples/F030R8_inst |
./examples/G0B1_gen |
./examples/G0B1_inst |
./examples/L432KC_gen_ad_toClang_ed |
./examples/L432KC_gen_ad_toClang_ed_instr |
This way you see in a quick way any needed adaptions for your target project to port trice to it.
The Readme.md files in the examples folder contain further helpful information.
2.5.1. Target Macros
The easiest and mostly sufficient way to use Trice on the target side is the Trice macro trice
which you can mostly use as a printf
replacement in legacy code. See TriceVsPrintfSimilaritiesAndDifferences.md for more details. Is uses the TRICE_DEFAULT_PARAMETER_BIT_WIDTH
value (usually 32), which is equal for all values. If you wish target stamps use Trice
for 16-bit ones or TRice
for 32-bit ones.
The macros
trice8
,trice16
,trice32
,trice64
Trice8
,Trice16
,Trice32
,Trice64
TRice8
,TRice16
,TRice32
,TRice64
are always usable and the number 8, 16, 32, 64 specifies the parameter width, which is equal for all values within one macro. They are partially disabled, when the value TRICE_SINGLE_MAX_SIZE is defined to be smaller than 104. For example with TRICE_SINGLE_MAX_SIZE == 8, TRice32
can have no parameter value (4 byte Trice header, 4 byte stamp) and trice8
can have up to 4 parameter values (4 byte Trice header, 4 byte values) Thatβs mainly to get compiler errors rather than runtime errors.
More examples:
Trice | Header | Stamp | max. Values | Trice Size |
---|---|---|---|---|
trice8 |
4 | 0 | 0 *1 byte | 4 |
β¦ | β¦ | β¦ | β¦ | β¦ |
trice8 |
4 | 0 | 12 *1 byte | 16 |
Trice8 |
4 | 2 | 0 *1 byte | 6 |
β¦ | β¦ | β¦ | β¦ | β¦ |
Trice8 |
4 | 2 | 12 *1 byte | 18 |
TRice8 |
4 | 4 | 0 *1 byte | 8 |
β¦ | β¦ | β¦ | β¦ | β¦ |
TRice8 |
4 | 4 | 12 *1 byte | 20 |
trice16 |
4 | 0 | 2 *2 byte | 8 |
Trice16 |
4 | 2 | 1 *2 byte | 8 |
trice32 |
4 | 0 | 1 *4 byte | 8 |
Trice32 |
4 | 2 | 1 *4 byte | 10 |
TRice32 |
4 | 4 | 2 *4 byte | 16 |
trice64 |
4 | 0 | 1 *8 byte | 12 |
TRice64 |
4 | 4 | 1 *8 byte | 16 |
β¦ | β¦ | β¦ | β¦ | β¦ |
TRice64 |
4 | 4 | 12 *8 byte | 104 |
The value TRICE_DEFAULT_PARAMETER_BIT_WIDTH is the parameter bit with for the macros trice
, Trice
, TRice
(without number). It can make sense to set this value to 16 on smaller machines.
The full uppercase macro TRICE
is a Trice macro only using inline code. Because the main design aim was speed, this was the original design. Then it became clear, that several hundred of TRICE
macros increase the needed code amount too much and that it is better to have just a function call instead of having inline macros. If speed matters use TRICE(id(0)
, TRICE(Id(0)
, TRICE(ID(0)
else use trice(iD(0)
, Trice(iD(0)
, TRice(iD(0)
or mix usage as you like. The lower case macros internally use TRICE
like code but each is only a function call and therefore needs less space.
2.5.2. Target Trice Stamps
-
If you wish to have your Trice messages stamped, most probably time stamped, add the 2 hardware specific macros/functions to your project (example in ./examples/F030R8_inst/Core/Inc/triceConfig.h and ./examples/F030R8_inst/Core/Src/stm32f0xx_it.c ). The time base is in your hands and is allowed to be different for the 16-bit and 32-bit stamps. Example:
//! ms32 is a 32-bit millisecond counter, counting circular in steps of 1 every ms. extern uint32_t ms32; #define TriceStamp16 (SysTick->VAL) // Counts from 31999 -> 0 in each ms. #define TriceStamp32 ms32
- In the code snippet above the 32-bit timestamp is used for milliseconds and the 16.bit timestamp is used as clock counter what allows fine grained time measurements.
-
In the screenshot below, the 16-bit timestamp is a parallel counter running between 0-9999 milliseconds, which allows to have 16-bit timestamps all the time and only every 10 seconds is a full 32-bit timestamp needed.
- The trice tool
-ts*
CLI switches allow customization. With-hs off
host time stamps are suppressed. - It is also possible to use the stamp option not for time stamps but for any values, like addresses or a voltage or a random number.
Hint: I usually have the 32-bit timestamp as millisecond counter and the 16-bit timestamp as systick counter to measure short execution times.
2.5.3. Trice Checks
- Optionally copy parts of ./_test/testdata/triceCheck.c to your project if you wish to perform some checks.
- Do not inlucde this file directly, because it could get changed when
updateTestData.sh
is executed inside the./test
folder. - The only-uppercase
TRICE*
macros include trice code sequences what can led to a significant code amount if you use plenty of them, whereas the lowercase macrostrice
,Trice
,TRice
and their relatives are just function calls and better suited to be used normally.
- Do not inlucde this file directly, because it could get changed when
- In your source files add line
#include "trice.h"
at the top. - In a function write a trice message like:
TRice( "1/11 = %g\n", aFloat( 1.0/11 ) );
. - In project root:
- Create empty file:
touch til.json
. trice insert
should perform automatically the following things (The numbers are just examples.):- Patch source.c to
TRice( iD(12363), "1/11 = %g\n", aFloat( 1.0/11 ) );
- C & H files containing
trice
macros, are only modified if needed (missing IDs or changed format strings).
- C & H files containing
- Extend
til.json
- If no
til.json
is found nothing happens. At least an empty file is needed (Safety feature).
- If no
- Patch source.c to
- Create empty file:
- When the program runs later, it should output something similar to
- Look into ./TriceVsPrintfSimilaritiesAndDifferences.md for options.
- Read ./TriceConfigProjectImageSizeOptimization.md if needed.
2.5.4. Communication Ports
- For RTT the SEGGER source is already included. See ./TriceOverRTT.md for more info.
- If RTT is used, no hardware specific adaptions needed and it is the fastest possible data transfer. But you cannot use it in the field usually.
- The direct trice mode is recommended for RTT. The single trice execution is a bit longer then, but the log is completely done in one shot. It takes about 100-150 processor clocks, aka 1-2 microseconds.
- Info: All deferred trice modes are faster in the runtime execution but the Trice logs appear slightly delayed. You can finetune the Trices down to only 3 Assembler instructions executable within 6 processor clocks. See ./TriceSpeed.md as example.
- For UART transfer add UART write functionality. The deferred mode is recommended for UART transfer.
- It is possible to log over several channels parallel and to select an ID range for each channel.
- An additional device, like local file, GPIO pin or SPI, is possible by providing an appropriate write functionality.
- See also ./TriceOverOneWire.md.
2.5.5. Target Code Overview
./src
: User Interface
File | description |
---|---|
trice.h & trice.c | trice runtime lib user interface, #include trice.h in project files, where to use TRICE macros. Add trice.c to your embedded device project. Add ./src to your compiler include path. |
triceDefaultConfig.h | This file contains the most probably settings and serves also as a reference for tuning your project triceConfig.h |
./src
: Internal Components (only partially needed according to configuration)
File | description |
---|---|
cobs.h | message packaging, alternatively for tcobs |
cobsEncode.c | message encoding, alternatively for tcobs |
cobsDecode.c | message decoding, normally not needed |
trice.h | trice lib interface |
trice.c | trice core lib |
trice8McuOrder.c | trice MCU endianness lib |
trice8McuReverse.c | trice MCU reverse endianness lib |
trice16McuOrder.c | trice MCU endianness lib |
trice16McuReverse.c | trice MCU reverse endianness lib |
trice32McuOrder.c | trice MCU endianness lib |
trice32McuReverse.c | trice MCU reverse endianness lib |
trice64McuOrder.c | trice MCU endianness lib |
trice64McuReverse.c | trice MCU reverse endianness lib |
SEGGER_RTT.h | Segger RTT code interface |
SEGGER_RTT.c | Segger RTT code |
tcobs.h | message compression and packaging interface |
tcobsv1Encode.c | message encoding and packaging |
tcobsv1Decode.c | message decoding and packaging, normally not needed |
tcobsv1Internal.h | message decoding and packaging internal interface |
trice8.h | 8-bit trice code interface |
trice8.c | 8-bit trice code |
trice16.h | 16-bit trice code interface |
trice16.c | 16-bit trice code |
trice32.h | 32-bit trice code interface |
trice32.c | 32-bit trice code |
trice64.h | 64-bit trice code interface |
trice64.c | 64-bit trice code |
triceAuxiliary.c | trice code for auxiliary interfaces |
triceDoubleBuffer.c | trice runtime lib extension needed for fastest deferred mode |
triceStackBuffer.c | trice runtime lib extension needed for direct mode |
triceRingBuffer.c | trice runtime lib extension needed for recommended deferred mode |
xtea.c | XTEA message encryption/decryption interface |
xtea.c | XTEA message encryption/decryption code |
- The tcobs*.* files are copied from https://github.com/rokath/tcobs/tree/master/Cv1. They are maintained there and extensively tested and probably not a matter of significant change.
- The SEGGER files are copied and you could check for a newer version at https://www.segger.com/downloads/jlink/.
2.5.6. User Code Adaption
- Replace all strings
puts
with the stringtrice
, when the string follows immediately. For runtime generated strings seetriceS
. - Replace all strings
printf
with the stringtrice
, when the format string follows immediately. -
Check for float and double format specifiers in the format strings. The appropriate parameters need to be covered with
aFloat()
ora double()
. Example:printf( "%d, %3.2f EUR, %g rate\n", i, price, change );
trice64( "%d, %3.2f EUR, %g rate\n", i, aFloat(price), aDouble(change) );
- Because double needs 8 bytes the trice macro in this case needs to be trice64 (see Trice Parameter Bit Widths).
-
Check for string format specifiers in the format strings. Put each in a separate trice message. Example:
printf( "name: %16s, surname: %32s, birthday: %4u-%02u-%02u\n", n, s, y, m, d);
trice( "name: %16s, ", n); trice( "surname: %32s, ", s ); trice( "birthday: %4u-%02u-%02u\n" y, m, d);
The Trice macros are designed for maximal execution speed and therefore we have to pay the price for their limited capabilities.
-
Optionally add tags to get color. Example:
puts( "A message");
trice( "msg:A message");
-
Add
#include trice.h
to all user files using trice.
2.5.7. Limitations
- The maximum parameter count per trice is 12, but buffer transfer alows up to 32764 bytes payload. See
triceB
and its relatives. - Each trice must fit into a single line in trice versions before v0.61.0.
-
Not ok before v0.61.0 but ok for later versions:
trice( "hello %u\n", year);
-
- But several trices can be in one line.
-
Ok:
trice( "hello %u\n", year); trice( "good time");
-
- Strings directly as parameter are possible now.
-
Ok from v0.61.0 with
trice insert
andtrice clean
:triceS( "hello %s\n", "world" );
-
Ok always:
s = "world"; TRICE_S( "hello %s\n", s ); #define WORLD "world" triceS( "hello %s\n", WORLD );
-
You should be aware that these parameter strings go into the target and slow down the execution. So, whenever a string is known at compile time it shuld be part of the Trice format string.
The Trice source code parser has very limited capabilities, so it cannot handle C-preprocessor string conatenation.
- Excluded trices are seen by the trice insert process.
-
Example: The following code will be patched and get an ID as well:
// trice( "Hi!" );
-
-
All parameters inside one trice have the same bit width. If for example there are a single double and 10 bytes values, the needed trice macro is
trice64
providing 8 bytes space for all parameter values, therefore increasing the transmit overhead. With the default TCOBS framing the overhead is marginal because of the compression. Also this can be handled by splitting into 2 trices:// 92 bytes: 4 bytes header plus 11 times 8 bytes trice64( "%g: %c%c%c%c%c%c%c%c%c%c", aDouble(3.14159), 61, 62, 63, 64, 65, 66, 67, 68, 69, 10 ); // 24 bytes: 4 bytes header plus 1 times 8 bytes plus 4 bytes header plus 8 times 1 byte trice64( "%g: ", aDouble(3.14159)); trice8( "%c%c%c%c%c%c%c%c%c%c", 61, 62, 63, 64, 65, 66, 67, 68, 69, 10 );
- See also 2.6. Avoid it.
2.5.8. Trice (Time) Stamps
- Trice messages can have no or 16-bit or 32-bit (time) stamps.
-
recommended (function calling) syntax:
trice( "hello %u\n", year); // no (time) stamp Trice( "hello %u\n", year); // 16-bit (time) stamp TRice( "hello %u\n", year); // 32-bit (time) stamp
-
legacy (inlining) syntax:
TRICE( id(0), "hello %u\n", year); // no (time) stamp TRICE( Id(0), "hello %u\n", year); // 16-bit (time) stamp TRICE( ID(0), "hello %u\n", year); // 32-bit (time) stamp
-
2.5.9. Trice Parameter Bit Widths
- The macros
trice
,Trice
,TRice
andTRICE
use 32-bit parameter values per default. SeeTRICE_DEFAULT_PARAMETER_BIT_WIDTH
inside src/triceDefaultConfig.h to change that. -
If for example the bit width of all trice parameters is 8-bit, it is writable as trice8 macro, reducing the transmitted byte count per parameter from 4 to 1:
char b[8] = {1,2,3,4,5,6,7,8}; // 36 bytes: 4 bytes plus 32 (8 times 4) bytes payload trice( "%02x %02x %02x %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);` // 12 bytes: 4 bytes plus 8 (8 times 1) bytes payload trice8( " %02x %02x %02x %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);` // 12 bytes: 4 bytes plus 8 (8 times 1) bytes payload in short notation. triceB( "deb: %02x\n", &b, sizeof(b) );
Hint: With the defaut TCOBS framing 8-bit values as 32-bit parameters typically occupy only 2-bytes during transmission.
2.6. Avoid it
2.6.1. Parser Limitation
Because the implemented source code parser for trice insert
and trice clean
is only a simple one, there is one important limitation:
- Do not use an unescaped singe double quote in source code comments. Example:
trice( "hi 0" );
// An "allowed" example comment.
trice( "hi 1");
// An \" allowed example comment.
trice( "hi 2");
// A " NOT allowed example comment. This disrupts the parsing.
trice( "hi 3");
// A " NOT allowed example comment. This enables the parsing after a disruption.
trice( "hi 4");
- The
trice insert
andtrice clean
will not see thetrice( "hi 3");
line here, but the compiler will mark an error then. - See also issue #427, issue #465 and see also Limited Trice Parser Capabilities.
2.6.2. Trice macros in header files
- There is nothing wrong, when putting trice macros into header files.
- But: When you use
trice insert
as pre-build command andtrice clean
as post build command, those header files get touched on each build and therefore all source code files including them will be re-translated every time. - For efficiency avoid that.
- With inventing the Trice cache this is of no relevance.
2.6.3. Trice macros inside other macros
- There is nothing wrong, when putting Trice macros into other macros.
- But: When running the self made macro, the location information of the inner trice macro will point to the self made macro definition and not to its execution location.
3. Build trice
tool from Go sources (you can skip that)
- Install Go.
- On Windows you need to install TDM-GCC if you wish to execute the CGO tests as well.
- Take the 64-bit variant when Go is 64-bit or take the 32-bit variant when Go is 32-bit. If mixed installations work I doubt.
- Recommendation: Minimal online installer.
- GCC is only needed to test the target C-code on the host.
- Make sure TDM-GCC is found first in the path, if you have several compilers installed.
- Other gcc variants could work also but not tested.
- Open a console inside the
trice
directory, recommended is the git-bash, when using Windows. - Check and install:
ms@DESKTOP-7POEGPB MINGW64 /c/repos/trice (master)
$ go clean -cache
ms@DESKTOP-7POEGPB MINGW64 /c/repos/trice (master)
$ go vet ./...
ms@DESKTOP-7POEGPB MINGW64 /c/repos/trice (master)
$ go test ./...
? github.com/rokath/trice/cmd/cui [no test files]
ok github.com/rokath/trice/cmd/stim 0.227s
ok github.com/rokath/trice/cmd/trice 0.577s
ok github.com/rokath/trice/internal/args 0.232s
ok github.com/rokath/trice/internal/charDecoder 0.407s
ok github.com/rokath/trice/internal/com 1.148s
ok github.com/rokath/trice/internal/decoder 0.412s [no tests to run]
? github.com/rokath/trice/internal/do [no test files]
ok github.com/rokath/trice/internal/dumpDecoder 0.388s
ok github.com/rokath/trice/internal/emitter 0.431s
ok github.com/rokath/trice/internal/id 0.421s
ok github.com/rokath/trice/internal/keybcmd 0.431s
ok github.com/rokath/trice/internal/link 0.404s
ok github.com/rokath/trice/internal/receiver 0.409s
ok github.com/rokath/trice/internal/tleDecoder 0.398s
? github.com/rokath/trice/internal/translator [no test files]
ok github.com/rokath/trice/internal/trexDecoder 0.391s
ok github.com/rokath/trice/pkg/cipher 0.377s
ok github.com/rokath/trice/pkg/endian 0.302s
ok github.com/rokath/trice/pkg/msg 0.299s
ok github.com/rokath/trice/pkg/tst 0.406s
To execute the target code tests, you can run test.sh
or cd
into _test
and run go test ./...
from there. ATTENTION: These tests run a significant long time (many minutes depending on your machine), because the Go - C border is crossed very often.
The last tests can last quite a while, depending on your machine.
ms@DESKTOP-7POEGPB MINGW64 /c/repos/trice (master)
$ go install ./cmd/trice/
Afterwards you should find an executable trice
inside $GOPATH/bin/ and you can modify its source code.
4. Embedded system code configuration
Check comments inside triceDefaultConfig.h and adapt your project configuration like shown in triceConfig.h as example.
5. trice
tool in logging action
With trice log -port COM12
you can visualize the trices on the PC, if for example COM12
is receiving the data from the embedded device at the 115200 default baudrate.
The following capture output comes from an (old) example project inside ../examples.
See ../_test/testdata/triceCheck.c for reference. The Trices can come mixed from inside interrupts (light blue ISR:...
) or from normal code. For usage with a RTOS, Trices are protected against breaks (TRICE_ENTER_CRITICAL_SECTION
, TRICE_LEAVE_CRITICAL_SECTION
). Regard the differences in the read SysTick values inside the GIF above These differences are the MCU clocks needed for one trice (~0,25Β΅s@48MHz).
Use the -color off
switch for piping output in a file. More convenient is the -lf auto
switch.
6. Encryption
- You can deliver your device with encrypted trices. This way only the service [wo]men is able to read the Trices.
- Implemented is XTEA but this is exchangeable.
- The to 8 byte padded blocks can get encrypted by enabling
#define ENCRYPT...
inside triceConfig.h. You need to add-password MySecret
astrice log
switch and youβre done. - Any password is usable instead of
MySecret
. Simply add once the-show
switch and copy the displayed passphrase into the triceConfig.h file. - The encryption takes part before the COBS encoding.
- TCOBS is usable but not recommended after encryption, because it cannot compress effective arbitrary data.
7. CLI Options for trice
tool
The trice tool is very easy to use even it has a plenty of options. Most of them normally not needed. The trice tool can be started in several modes (sub-commands), each with several mandatory or optional switches. Switches can have parameters or not.
trice sub-command -switch1 -switch2 parameter -switch3 ...
Which sub-command switches are usable for each sub-command is shown with trice help -all
. This gives also information about their default values.
Info for a special sub-command is shown with trice h -l
, trice h -z
, β¦ .
8. Trice command line examples
- The trice tool has many command line options, but is easy to use with default values.
- No config file implemented yet. But the command history is usable for example inside the bash, simply enter CTRL-R and start typing
trice...
and you can select from the history.
8.1. Common information
trice h -all
shows all options of the current version.trice ver
prints version information.trice s
shows you all found serial ports for your convenience.trice l -p COM17
could fail if something is wrong. Additional switches are for help tracking the issue:- Use log witch
-s[howInputBytes]
to check if any bytes are received at all. - With
-debug
you can see the [T]COBS packages and decoded Trice packages.
- Use log witch
8.2. Further examples
8.2.1. Automated pre-build insert command example
- Scan directories
../src
,../lib/src
and./
to insert the IDs there and extend list file../../../til.json
trice i -v -i ../../../til.json -src ../src -src ../lib/src -src ./
This is a typical line you can add to your project as an automatic pre-compile step.
8.2.2. Some Log examples
- Log trice messages on COM3 8N1 115200 baud
trice log -i ./myProject/til.json -p=COM3
- Log trice messages on COM3 8N1 9600 baud and use default til.json
trice l -s COM3 -baud=9600
8.2.3. Logging over a display server
- Start displayserver on ip 127.0.0.1 (localhost) and port 61497
trice ds
- Log trice messages on COM3 and display on display server
trice l -ds -p COM3
- Shutdown remote display server on IP 192.168.1.23 port 45678
trice sd -r 192.168.1.23:45678
8.2.4. Logfile output
trice l -p COM3 -logfile auto
This creates a new logfile 2022-05-16_2216-40_trice.log
with the actual timestamp on each trice start.
trice l -p COM3 -logfile trice.log
This creates a new logfile trice.log
on first start and appends to it on each next trice start.
Logfiles are text files one can see with 3rd party tools. Example: cat trice.log
. They contain also the PC reception timestamps if where enabled.
8.2.5. Binary Logfile
trice l -p COM3 -binaryLogfile auto
This creates a new binary logfile 2022-05-16_2216-40_trice.bin
with the actual timestamp on each trice start.
trice l -p COM3 -binaryLogfile trice.bin
This creates a new binary logfile trice.bin
on first start and appends to it on each next trice start.
Binary logfiles store the trice messages as they come out of the target in binary form. They are much smaller than normal logfiles, but the trice tool with the til.json is needed for displaying them and the PC timestamps are the displaying time: trice l -p FILEBUFFER -args trice.log
.
Binary logfiles are handy in the field for long data recordings.
When using RTT, the data are exchanged over a file interface. These binary logfiles are stored in the project [./temp] folder and accessable for later view: trice l -p FILEBUFFER -args ./temp/logfileName.bin
. Of course the host timestamps are the playing time then.
8.2.6. TCP output
trice l -p COM3 -tcp 127.0.0.1:23
This additionally sends trice output to a 3rd party TCP listener, for example like Putty:
8.2.7. TCP input
trice l -p TCP4 -args "192.168.2.3:45678"
This expects a TCP4 server at IP address 192.168.2.3
with port number 45678
to read binary Trice data from.
8.2.8. Stimulate target with a user command over UART
Sometimes it is handy to stimulate the target during development. For that a 2nd screen is helpful what is possible using the display server option:
8.2.9. Explpore and modify channels and their colors
See file TriceColor.md
8.2.10. Location Information
When running trice insert
, a file li.json
is created, what you can control with the -li|locationInformation
switch. During logging, when li.json
is found, automatically the filename and line number is displayed in front of each log line, controllable with the -liFmt
switch. This information is correct only with the right version of the li.json
file. That is usually the case on the PC during development. Out in the field only the til.json
reference is of importance. It serves as an accumulator of all firmware versions and usually the latest version of this file is the best fit. The li.json
file should stay with the software developer only and needs no version control in the usual case because it is rebuild with each compilation, when trice i
is a prebuild step. When trice clean
is used, the file li.json
should go into the version management too to secure that identical trices get the same ID back.
9. Limitations
9.1. Permanent Limitations
9.1.1. Limitation TRICE in TRICE not possible
- No-Good Example:
int f0( void ){ TRICE( "msg:f0\n"); return 0; }
void f1( void ){ TRICE( "No; %d", f0() ); }
- This will compile normally but corrupt TRICE output.
The reason is: When f1() gets active, the βNoβ Trice header is created, than the f0() Trice is executed and afterwards the βNoβ Trice tail is written. This works well during compile time but causes a mismatch during runtime.
- Workaround:
int f0( void ){ TRICE( "msg:f0\n"); return 0; }
void f1( void ){ int x = f0(); TRICE( "Yes: %d", x ); }
9.2. Current Limitations
9.2.1. String Concatenation Within TRICE Macros Not Possible
String concatenation within TRICE macros does not work. The reason lays inside the way the trice tool parser works:
void f0( void ){ TRICE( "msg:" ## "Hello\n" ); } // ERROR!
To implement this would need to build a trice preprocessor or to run the C preprocessor first and to modify the preprocessor output with the trice tool. That would make things unneccessary complicate and fragile for now.
9.2.2. Limited Trice Parser Capabilities
The Trice tool internal parser has only limited capabilities. In works well in most cases, but could led to problems in some cases. The compiler run will for sure end up with some error messages in the following examples, so the developer can fix the code.
An example, provided by @KammutierSpule, is this:
- started from a empty li.json/til.json
void trice0_test() {
Trice0( "OK");
Trice( InvalidUse );
Trice( "OK", Variable );
}
- run
trice insert
void trice0_test() {
Trice0( iD(2740), "OK"); // ok, iD is added
Trice( InvalidUse ); // no warning or error
Trice( "OK", Variable ); // id is not added / inserted
}
As said, the compiler will complain about that in any case.
10. Additional hints
10.1. Pre-built executables are available
See https://github.com/rokath/trice/releases.
10.2. Configuration file triceConfig.h
- When setting up your first project you need a
triceConfig.h
file. - You should not use the
./_test/cgo.../triceConfig.h
directly, because these are customized for internal tests with CGO. But you can use their settings as helper for a starting point. - Please choose one of the
./examples/*_inst/triceConfig.h
files as starting point. - Comparing them and understandig the differences helps quick starting.
- The file triceDefaultConfig.h contains all possible config keys with descriptions.
10.3. Setting up the very first connection
If you see nothing in the beginning, what is normal ;-), add the -s
(-showInputBytes
) switch to see if any data arrive. There is also a switch -debug
showing you the received packages, if you are interested in.
10.4. Avoid buffer overruns
It is your responsibility to produce less data than transmittable. If this is not guarantied, a data loss is not avoidable or you have to slow down the user application. The buffers have an optional overflow protection (TRICE_PROTECT
), which is enabled by default. Recommendation: Make the buffer big and emit the maxDepth cyclically, every 10 or 1000 seconds. Then you know the needed size. It is influenced by the max Trice data burst and the buffer switch interval. See ./example/exampleData/triceLogDiagData.c for help.
If the target application produces more Trice data than transmittable, a buffer overrun can let the target crash, because for performance reasons no overflow check is implemented in versions before v0.65.0. Such a check is added now per default using TRICE_PROTECT
, but the Trice code can only throw data away in such case. Of course you can disable this protection to get more speed.
Configuring the ring buffer option with TRICE_PROTECT == 0
makes buffer overruns not completely impossible, because due to partial Trice log overwrites, false data are not excluded anymore and overwriting the buffer boundaries is possible, because of wrong length information. Also losses will occur when producing more data than transmittable. This is detectable with the cycle counter. The internal 8-bit cycle counter is usually enabled. If Trice data are lost, the receiver side will detect that because the cycle counter is not as expected. There is a chance of 1/256 that the detection does not work for a single case. You can check the detection by unplugging the trice UART cable for a time. Also resetting the target during transmission should display a cycle error.
Gennerally it is recommended to enable TRICE_PROTECT
during development and to disable it for performance, if you are 100% sure, that not more data are producable than transmittable.
Important to know: If the TRICE_PROTECT
code inhibits the writing into a buffer, there will be later no cycle error because a non existing Trice cannot cause a cycle error. Therefore the TriceDirectOverflowCount
and TriceDeferredOverflowCount
values exist, which could be monitored.
10.5. Buffer Macros
(Examples in ../_test/testdata/triceCheck.c)
Macro Name | Description | Β | Β |
---|---|---|---|
triceS |TriceS |TRiceS |TRICE_S |
Output of runtime generated 0-terminated strings. | Β | Β |
triceN |TriceN |TRiceN |TRICE_N |
Is for byte buffer output as string until the specified size. It allows limiting the string size to a specific value and does not rely on a terminating 0. If for example len = 7 is given and βHello\0World\nβ is in the buffer, the byte sequence βHello\0Wβ is transmitted but the trice tool probably shows only βHelloβ. | Β | Β |
trice8B |Trice8B |TRice8B |TRICE8_B |
Is for byte buffer output according to the given format specifier for a single byte. | Β | Β |
trice16B |Trice16B |TRice16B |TRICE16_B |
Is for 16-bit buffer output according to the given format specifier for a 16-bit value. | Β | Β |
trice32B |Trice32B |TRice32B |TRICE32_B |
Is for 32-bit buffer output according to the given format specifier for a 32-bit value. | Β | Β |
triceB |TriceB |TRiceB |TRICE_B |
Is buffer output according to the given format specifier for a default unit according to configuration (8 | 16 | 32-bit value). |
10.6. Logfile viewing
Logfiles, trice tool generated with sub-command switch -color off
, are normal ASCII files. If they are with color codes, these are ANSI escape sequences.
- Simply
cat trice.log
. One view option is alsoless -R trice.log
. The Linux commandless
is also available inside the windows git bash. - Under Windows one could also download and use ansifilter for logfile viewing. A monospaced font is recommended.
- See also Color issues under Windows
10.7. Using the trice
tool with 3rd party tools
Parallel output as logfile, TCP or binary logfile is possible. See examples above.
10.8. Several targets at the same time
You can connect each target over its transmit channel with an own trice instance and integrate all transmissions line by line in an additional trice instance acting as display server. See https://github.com/rokath/trice#display-server-option.
10.9. Executing go test -race -count 100 ./...
The C-code is executed during some tests. Prerequisite is an installed GCC.
10.10. Direct TRICE Out (TRICE_MODE TRICE_STACK_BUFFER) could cause stack overflow with -o0 optimization
As discussed in issue #294 it can happen, that several TRICE macros within one function call increase the stack usage more than expected, when compiler optimization is totally switched off.
10.11. Cycle Counter
- The trice tool expects the first cycle counter to start with 0xC0 (=192). If the target is already running and you connect the trice tool then, the first message is marked with βCYCLE: ? not equal expected value 192 - adjusting. Now 1 CycleEventsβ.
- If the target is resetted asynchronous, the trice tool receives a cycle counter 192. Most probably the last cycle counter was not 191, so this triggers also a messageΒ with βCYCLE: 192 not equal expected value ?- adjusting. Now n CycleEventsβ.
- In the Trice tool is some heuristics to suppress such obvious false positives.
11. Switching Trice ON and OFF
11.1. Target side compile-time Trice On-Off
- If your code works well after checking, you can add
#define TRICE_OFF 1
just before the#include "trice.h"
line and no trice code is generated anymore for that file, so no need to delete or comment outTRICE
macros:
#define TRICE_OFF 1
#include "trice.h"
void fn(void) {
trice( iD(123), "Hi"); // Will generate code only, when TRICE_OFF == 0.
trice( "Lo"); // Will generate code only, when TRICE_OFF == 0.
}
With #define TRICE_OFF 1
macros in this file are ignored completely by the compiler, but not by the trice tool. In case of re-constructing the Trice ID List these no code generating macros are regarded and go into (or stay inside) the ID reference list.
- Hint from @escherstair: With
-D TRICE_OFF=1
as compiler option, the trice code diappears completely from the binary. - No runtime On-Off switch is implemented for several reasons:
- Would need a control channel to the target.
- Would add little performance and code overhead.
- Would sligtly change target timing (testing).
- User can add its own switches anywhere.
- The short
TRICE
macro code is negligible. - The trice output is encryptable, if needed.
- Because of the low Trice bandwidth needs and to keep the target code as clear as possible the runtime On-Off decision should be done by the trice tool.
11.2. Host side Trice On-Off
- The PC trice tool offers command line switches to
-pick
or-ban
for trice channels and will be extended with display switches. - A trice tool
-logLevel
switch is usable too.
12. Framing
- Trice messages are framed binary data, if framing is not disabled.
- Framing is important for data disruption cases and is done with TCOBS (has included data compression) but the user can force to use COBS, what makes it easier to write an own decoder in some cases or disable framing at all.
- Change the setting
TRICE_FRAMING
insidetriceConfig.h
and use the trice tool-packageFraming
switch accordingly.
- Change the setting
- For robustness each Trice can get its own (T)COBS package (
TRICE_DEFERRED_TRANSFER_MODE == TRICE_SINGLE_PACK_MODE
). That is configurable for transfer data reduction. Use#define TRICE_DEFERRED_TRANSFER_MODE TRICE_MULTI_PACK_MODE
insidetriceConfig.h
(is now default). This allows to reduce the data size a bit by avoiding many 0-delimiter bytes but results in some more data loss in case of data disruptions.
13. Optional XTEA Encryption
- If XTEA is used, the encrypted packages have a multiple-of-8 byte length containing 1-7 padding bytes.
- The optional decryption is the next step after unpacking a data frame.
- Enabling XTEA, automatically switches to COBS framing. There is no need to use the trice tool
-packageFraming
switch in that case because the trice tool, when getting the CLI switch-password "phrase"
automatically assumes COBS encoded data, overwriting the default value for-packageFraming
.
14. Endianness
- To interpret a decoded package, itΒ΄s endianness needs to be known.
- For efficiency, binary trice data are normally stored and transmitted in MCU endianness and the trice tool expects binary data in little endian format as most MCUs are little endian.
- On big endian MCUs the compiler switch
TRICE_MCU_IS_BIG_ENDIAN
needs to be defined as 1 andTRICE_TRANSFER_ORDER_IS_BIG_ENDIAN
should have the same value. The trice tool has a CLI switch βtriceEndiannessβ which needs to be set to βbigEndianβ then. - If trice transmit data are needed to be not in MCU order for some reason, that increases the critical trice storage time and target code amount.
- De facto different values for
TRICE_MCU_IS_BIG_ENDIAN
andTRICE_TRANSFER_ORDER_IS_BIG_ENDIAN
are mainly used to test the Trice CLI switch-triceEndianness bigEndian
automatically.
15. TRICE
(Time)Stamps
- Each Trice message can carry stamp bits, which are free usable like for time, addressing or filtering.
- By selecting the letter case (trice, Trice, TRice) you decide for each single Trice macro about the stamp size.
-
Default notation (function call):
notation stamp size remark trice( iD(n), "...", ...);
0-bit no stamp at all, shortest footprint Trice( iD(n), "...", ...);
16-bit calls internally uint16_t TriceStamp16( void )
for trice message stampingTRice( iD(n), "...", ...);
32-bit calls internally uint32_t TriceStamp32( void )
for trice message stamping -
No upper case macro, like
TRICE_S
works with the internaliD(n)
macro. They needid(n)
,Id(n)
orID(n)
. See next table. -
Legacy notation (code inlining):
notation stamp size remark TRICE( id(n), "...", ...)
0-bit no stamp at all, shortest footprint TRICE( Id(n), "...", ...)
16-bit calls internally uint16_t TriceStamp16( void )
for trice message stampingTRICE( ID(n), "...", ...)
32-bit calls internally uint32_t TriceStamp32( void )
for trice message stamping
It is up to the user to provide the functions TriceStamp16
and/or TriceStamp32
. Normally they return a Β΅s or ms tick count but any values are allowed.
16. Binary Encoding
16.1. Symbols
Symbol | Meaning |
---|---|
i |
ID bit |
I |
iiiiiiii = ID byte |
n |
number bit |
z |
count selector bit |
s |
stamp selector bit |
N |
znnnnnnnn = count selector bit plus 7-bit number byte |
c |
cycle counter bit |
C |
z==0 ? cccccccc : nnnnnnnn = cycle counter byte or number byte extension |
t |
(time)stamp bit |
T |
tttttttt = (time)stamp byte |
d |
data bit |
D |
dddddddd = data byte |
... |
0 to 32767 data bytes |
"..." |
format string |
W |
bit width 8, 16, 32 or 64 (uW stands for u8, u16, or u64) |
x |
unspecified bit |
X |
=xxxxxxxx unspecified byte |
16.2. Package Format
- Because of the TCOBS or COBS package framing, the package sizes are detectable by the trice tool without additionlal length information.
-
All decoded frames of 0-, 1-, 2- and 3-byte size are considered as user data and ignored by the trice tool.
bytes Comment `` This is an empty package, which can have also a meaning. It is detectable by 2 consecutive 0-delimiter bytes. X
1-byte message, reserved for extensions or user data X
X
2-byte message, reserved for extensions or user data X
X
X
3-byte message, reserved for extensions or user data - In decoded frames with >= 4-bytes the first 2 bytes contain 2 stamp selector bits at the most significant position in the known endianness.
- The
0
stamp selector is usable for any user encoding. The trice tool ignores such packages. -
The
1
,2
and3
stamp selector bits are followed by the 14-bit ID.16-bit groups Stamp Selector (2 msb) Comment Endianness sizes _____ 00xxxxxxX ...
0 >= 4-byte message, reserved for extensions or user data ___ u16 ?...?
_____ 01iiiiiiI NC ...
1 >= 4-byte message, Trice format without stamp ___ u16 u16 [uW] ... [uW]
_____ 10iiiiiiI TT NC ...
2 >= 4-byte message, Trice format with 16-bit stamp ___ u16 u16 u16 [uW] ... [uW]
10iiiiiiI 10iiiiiiI TT NC ...
2 First 16bit are doubled. Info over -d16
trice switch.u16 u16 u16 u16 [uW] ... [uW]
_____ 11iiiiiiI TT TT NC ...
3 >= 4-byte message, Trice format with 32-bit stamp ___ u16 u32 u16 [uW] ... [uW]
- The stamp selector
2
encoding has 2 possibilities. When usingTRICE_DIRECT_SEGGER_RTT_32BIT_WRITE
or encryption, for alignment reasons the first 16bit ID field is doubled. The trice tool discards these 2 doubled bytes when the CLI switch-d16
is given or encryption is active. - Default endianness is little endian as most MCUs use little endianness. Otherwise the
-triceEndianness=bigEndian
CLI switch is needed. - The receiving tool evaluates firstly the 2 stamp bits and follows some rules:
- 0: reserved -> ignore the whole package (discard) or treat it as user data.
- 1: next 14 bits are the ID followed by 2 bytes u16=NC and optional parameter values. Package size is >= 4 bytes.
- 2 and
-d16
CLI switch not provided: next 14 bits are the ID and convert then u16=TT=stamp16 followed by 2 bytes u16=NC and optional parameter values. Package size is >= 6 bytes. - 2 and
-d16
CLI switch provided: next 14 bits are the ID, discard 2 following bytes and convert then u16=TT=stamp16 followed by 2 bytes u16=NC and optional parameter values. Package size is >= 8 bytes. - 3: next 14 bits are the ID and convert then u32=TTTT=stamp32 followed by 2 bytes u16=NC and optional parameter values. Package size is >= 8 bytes.
- use ID to get parameters width
W
=8,16,32,64 from file til.json and and parameters count and convert appropriate.- Within one trice message the parameter bit width
W
does not change.
- Within one trice message the parameter bit width
17. Trice Decoding
The 14-bit IDs are used to display the log strings. These IDs are pointing in two reference files.
17.1. Trice ID list til.json
- This file integrates all firmware variants and versions and is the key to display the message strings. With the latest version of this file all previous deployed firmware images are usable without the need to know the actual firmware version.
- The files
til.json.h
,til.json.c
and the like are generated to help writing an own trice decoder tool in your preferred language. Usetrice i -v
for it. That can be interesting in environments, where Go compiled binaries not executable, like PCs running QNX OS.
17.2. Trice location information file li.json
- If the generated
li.json
is available, the trice tool automatically displays file name and line number. But that is accurate only with the exact matching firmware version. That usually is the case right after compiling and of most interest at the developers table. - The trice tool will silently not display location information, if the
li.json
file is not found. For in-field logging, the option-showID string
could be used. This allows later an easy location of the relevant source code. - An other option is to record the binary trice messages and to play them later with the trice tool using the correct
li.json
.
18. Trice ID Numbers
18.1. ID number selection
- The default encoding TREX supports 14-bit IDs, so over 16000 IDs possible. Other encodings can work with other ID sizes.
trice("Hi!\n");
β‘trice i
β‘trice( iD(12345), "Hi!\n");
β‘trice c
β‘trice("Hi!\n");
- The ID
12345
is a number assigned totrice( "Hi!\n");
in the above example.- It is a so far unused number, according to rules you can control:
- The
-IDMethod
switch allows a selection method for new IDs.- Per default new IDs determined randomly to keep the chance low, that several developers grab the same ID.
- Example:
trice insert -IDMin 1000 -IDMethod upward
will choose the smallest free ID >= 1000.- This allows to use the ID space without wholes.
- The
-IDMin
and-IDMax
switches are usable to control the ID range, a new ID is selected from, making it possible to divide the ID space. Each developer can gets it region.- Example:
trice insert -IDMin 6000 -IDMax 6999
will choose new randomly IDs only between 6000 and 6999.
- Example:
- The
- It is a so far unused number, according to rules you can control:
- It is possible to give each trice tag an ID range making it possible to implement Trice tag specific runtime on/off on the target side if that is needed. This could be interesting for routing purposes also. Please run
trice help -insert
and read about the-IDRange
switch for more details.
18.2. ID number usage and stability
- If you write
trice( "msg:%d", 1);
again on a 2nd location, the copy gets a different ID, because each Trice gets its own ID. - If you change
trice( "msg:%d", 1);
totrice8( "msg:%d", 1);
, to reduce the needed parameter space, a new ID is assigned. That is because the parameter bit width is implicit a part of the now changed Trice. If you change that back, the previous ID is assigned again. - If you change
trice( "msg:%d", 1);
toTRice8( "msg:%d", 1);
, to get a 32-bit stamp, the associated ID remains unchanged. That is because the optional stamp is not a part of the Trice itself. - IDs stay constant and get only changed to solve conflicts.
- To make sure, a single ID will not be changed, you could change it manually to a hexadecimal syntax.
- This lets the
trice insert
command ignore suchTRICE
macros and therefore a full til.json rebuild will not add them anymore. Generally this should not be done, because this could cause future bugs. - It is possible to assign an ID manually as decimal number. It will be added to the ID list automatically during the next
trice i|c
if no conflicts occur.
- This lets the
- If a Trice was deleted inside the source tree (or file removal) the appropriate ID stays inside the ID list.
- If the same string appears again in the same file this ID is active again.
- If a trice occurs more than one time, each occurrence gets a different ID. If then 2 of them disappear, their ID numbers stay in
til.json
. If then one of them comes back, it gets its ID back.
18.3. Trice ID 0
- The trice ID 0 is a placeholder for βno IDβ, which is replaced automatically during the next
trice insert
according to the used trice switches-IDMethod
,-IDMin
andIDMax
.- It is sufficient to write the TRICE macros just without the
id(0),
Id(0),
ID(0),
. It will be inserted automatically according the-stamp
switch.
- It is sufficient to write the TRICE macros just without the
19. Trice ID management
19.1. Trices inside source code
19.1.1. Trices in source code comments
TRICE
macros commented out, are visible for thetrice insert
command and therefore regarded.- Example:
// TRICE( Id(12345), "Hi!\n" );
is still regarded by thetrice i
.
- Example:
- During
trice insert
TRICE macros, commented out, are treated in the same way as active TRICE macros. Even after deletion their content stays inside til.json. This is intensionally to get best stability across several firmware versions or variants. - The trice tool does treat trice statements inside comments or excluded by compiler switches also.
19.1.2. Different IDs for same Trices
- When the same Trice is used several times with identical IDs, after copying, and
trice insert
is called, only one ID survives in the source code.
19.1.3. Same IDs for different Trices
- If duplicate IDβs with different format strings found inside the source tree (case several developers or source code merging) one ID is replaced by a new ID. The probability for such case is low, because of the default random ID generation.
- Also you can simply copy a Trice statement and modify it without dealing with the ID.
- The trice tool will detect the 2nd (or 3rd) usage of this ID and assign a new one, also extending the ID list.
- That is done silently for you during the next
trice insert
.
20. ID reference list til.json
- The
trice insert
command demands a til.json file - it will not work without it. That is a safety feature to avoid unwanted file generations. If you are sure to create a new til.json file, create an empty one:touch til.json
. - The name til.json is a default one. With the command line parameter
-i
you can use any filename. - It is possible to use several til.json files - for example one for each target project but it is easier to maintain only one *til.json- file for all projects.
- The ID reference list keeps all obsolete IDs with their format strings allowing compatibility to former firmware versions.
- One can delete the ID reference list when IDs inside the code. It will be reconstructed automatically from the source tree with the next
trice clean
command, but history is lost then. - Keeping obsolete IDs makes it more comfortable during development to deal with different firmware variants at the same time.
20.1. til.json Version control
- The ID list should go into the version control repository of your project.
- To keep it clean from the daily development garbage one could delete the til.json, then check-out again and re-build just before check-in. A small script could do that.
- For a firmware release it makes sense to remove all unused IDs from til.json.
- Just delete the til.json contents and run
trice clean
.
- Just delete the til.json contents and run
- An other option is to delete til.json just before a release build and then check-in the new generated til.json.
For the no-ids option deleting til.json should not not be done when the sources are without IDs. That would result in a loss of the complete ID history and a assignment of a complete new set of IDs.
20.2. Long Time Availability
- You could place a download link for the trice tool and the used til.json list.
- Link a compressed/encrypted til.json file as resource into the target binary and optionally get it back long years later in a safe way.
- Optionally add the (compressed/encrypted) ID reference list as resource into the target FLASH memory to be sure not to loose it in the next 200 years.
21. The trice insert
Algorithm
21.1. Starting Conditions
- Before
trice i
is executed on a source tree, the starting conditions are partially undefined:- A trice ID list file
til.json
file must exist, but it is allowed to be empty.- The
til.json
is a serialized key-value map, where- the keys are the IDs i and
- the values are Trice format string structs (bit width plus format string) named f.
- When de-serializing, it is not impossible, that an ID is used more than one times. This can only happen, when til.json was edited manually, what normally is not done.
- The trice tool will report that as error and stop.
- This ID look-up is the key-value map
idToFmt TriceIDLookUp
asmap[TriceID]TriceFmt
.- Each ID i as key, points to one and only one f.
- The TriceFmt structs contains the parameter width and the format string.
- The idToFmt is reverted then into
fmtToId triceFmtLookUp
as map[TriceFmt]TriceIDs.TriceIDs
is a triceID slice because the identical f can have several ids (no shared IDs).- The format struct f look-up map fmtToId is used internally for faster access and always in sync with idToFmt.
- idToFmt and fmtToId together are named lu.
- The
- A location information file
li.json
may exist or not.- The
li.json
is a serialized key-value mapidToLocRef TriceIDLookUpLI
, amap[TriceID]TriceLI
, where- the keys are the IDs i and
- the values are the location information (filename, line and position in line) structs.
- Each ID as key points to one and only one location information.
- The
- A trice ID list file
- The
til.json
IDs may occur in the source tree not at all, once or several times. Also it is not guarantied, that the source tree Trices match thetil.json
value.- That is possible after code edit, for example or code copied or modified.
- One and only one position is used and relevant, all others are ignored. If no
til.json
exists on the expected location the user must provide one, at least an empty file.
- The
li.json
IDs may occur in the source tree not at all, once or several times. Also it is not guarantied, that the source tree Trices match theli.json
value.- One and only one position is used and relevant, all others are ignored. If no
li.json
exists on the expected location trice insert creates one there.
- One and only one position is used and relevant, all others are ignored. If no
- The src tree can contain IDs not present inside
til.json
. This state is seldom, for example after adding sources containing IDs.
21.2. Aims
- The
trice insert
main aim is to have a consistent state betweentil.json
,li.json
and the source tree with no ID used twice. - Also the changes should be minimal.
- As a general rule lu is only extendable.
- li is rebuild from scratch.
- For faster operation files will be processed parallel.
- To keep the ID management simple, the
insert
operation acts βper fileβ. That means, that in case a file is renamed or code containing trice statements is copied to an other file, new IDs are generated for the affectes trices.- File name changes occur are not that often, so tha should be acceptable.
21.3. Method
21.3.1. insert
Initialization
// insertIDsData holds the insert run specific data.
type insertIDsData struct {
idToFmt TriceIDLookUp // idToFmt 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.
fmtToId triceFmtLookUp // fmtToId is a trice fmt lookup map (reversed idToFmt for faster operation) and kept in sync with idToFmt. Each fmt can have several trice IDs (slice).
idToLocRef TriceIDLookUpLI // idToLocInf 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.
itemToId TriceItemLookUpID // itemToId is a trice item lookup ID map, extended from source tree during SubCmdIdInsert after each found and maybe modified trice item.
idToItem TriceIDLookupItem // idToItem is a trice ID lookup item map (reversed itemToId for faster operation) and kept in sync with itemToId.
}
- Create a
insertIDsData
instance. - De-serialize
til.json
intoidToFmt
andfmtToId
. On error abort and report for manual correction. One result is a slice with used IDs. - De-serialize
li.json
intoidToLocRef
. On error abort and report for manual correction. As result the slice with used IDs is extended.- If
li.json
contains IDs not already insidetil.json
, these are reported as warning. idToLocRef
stays untouched and is used only in cases when identical f are found.
- If
- Create a slice
IDSpace
with numbers IDmin β¦ IDmax (1 β¦ 16383, or 1000 β¦ 1999 if specified in the command line that way) - Remove all used IDs from
IDSpace
.- If used IDs outside IDmin and IDmax, for example IDmin=1000, IDmax=1999 and some used IDs are bigger or smaller these are not removable from IDroom what is ok.
-
Create empty
itemToId
andidToItem
. - Walk the src and create a source tree map STM with
- key=
Trice+LI
and - value=ID.
- key=
- During STM creation use these rules:
- If the next found f src ID == n != 0:
- If ID n already inside STM set ID = 0 (that is brutal but ok)
- Otherwise extend STM with ID n and remove n from IDroom
- It is possible, f is used n times with different IDs, so that is no problem.
- It is possible, f is used n times with the same ID, so the first occurrence is the winner.
- If the next found f src ID == 0 (normal case after trice z):
- Look in flu
- If not there, create new id and extend STM.
- The new ID is βnewβ, so forbidden to be inside ilu.
- If it is accidentally somewhere in the so far unparsed src, we do not know that and therefore do not care about.
- That is a seldom case and not worth to parse the source tree twice all the time.
- Patch id into source and extend STM.
- If the ID slice has len 1 (usually the case), take that n, extend STM and remove f from flu.
- That is important because f could be copied before.
- If the ID slice has a len > 1 (several IDs on the same string) check li
- If li is empty, just remove the first id from the slice and extend STM
- Loop over slice IDs
- If a file matches, take the first occurrence, extend STM and remove id from the ID slice
- If no file matches do the same as when li is empty.
- That means, after file renaming or code copying between files during trice z state, new IDs are generated for that parts.
- That is only for same f with several IDs cases
- File changes during trice i state are ok, because STM is generated with the IDs inside the sources.
- If not there, create new id and extend STM.
- Look in flu
- If the next found f src ID == n != 0:
Until here the algorithm seem to be ok.
- STM is not needed but maybe helpful during debugging.
-
STM than is usable to regenerate li.json and to extend til.json
- If after
trice i
atrice z
and atrice i
again is executed, all IDs are expected to be at the same place again. If in betweentrice i
, an optionaltrice z
and atrice i
src was edited, most IDs are expected to be at the same place again.
21.4. User Code Patching (trice insert
)
-
A Trice ID is inserted by
trice insert
as shown in the table:Unpatched User Code After trice insert
Remark trice( "Hi!\n");
trice( iD(12345), "Hi!\n");
no stamps Trice( "Hi!\n");
Trice( iD(12345), "Hi!\n");
16-bit stamps TRice( "Hi!\n");
TRice( iD(12345), "Hi!\n");
32-bit stamps -
Legacy code is handled this way:
Unpatched User Code After trice insert
Remark TRICE( "Hi!\n");
TRICE( id(12345), "Hi!\n");
no stamps after trice i -defaultStampSize 0
TRICE( "Hi!\n");
TRICE( Id(12345), "Hi!\n");
16-bit stamps after trice i -defaultStampSize 16
TRICE( "Hi!\n");
TRICE( ID(12345), "Hi!\n");
32-bit stamps after trice i -defaultStampSize 32
TRICE( id(0), "Hi!\n");
TRICE( id(12345), "Hi!\n");
no stamps TRICE( Id(0), "Hi!\n");
TRICE( Id(12345), "Hi!\n");
16-bit stamps TRICE( ID(0), "Hi!\n");
TRICE( ID(12345), "Hi!\n");
32-bit stamps -
A pre-build step
trice insert
generates theId(12345)
part. Examples:trice i
in your project root expects a til.json file there and checks sources and til.json for changes to insert.trice i -v -i ../../../til.json -src ../src -src ../lib/src -src ./
is a typical case as automated pre-build step in your project settings telling trice to scan the project dir and two external directories. Eventrice i
is fast, it is generally quicker to search only relevant places.
21.5. User Code Patching Examples
- A Trice ID is modified as shown in these cases:
-
Previously inserted (patched) user code copied to a different location:
trice(iD(12345), "Hi!\n"); // copied trice(iD(12345), "Hi!\n"); // original trice(iD(12345), "Hi!\n"); // copied
-
After updating (patching) again:
trice(iD(12345), "Hi!\n"); trice(iD( 1233), "Hi!\n"); // re-patched trice(iD( 1234), "Hi!\n"); // re-patched
- If the code is copied inside the same file, the first occurrence after the copy stays unchanged and the following are modified.
- If the code is copied to other files only, the copies get new IDs.
-
Previously inserted (patched) user code copied and modified:
trice(iD(12345), "Ha!\n"); // copied and modified trice(iD(12345), "Hi!\n"); // original trice(iD(12345), "Ha!\n"); // copied and modified
-
After updating (patching) again:
trice(iD( 2333), "Ha!\n"); // re-patched trice(iD(12345), "Hi!\n"); // unchanged trice(iD( 1234), "Ha!\n"); // re-patched
-
If the code is copied to other files, it is re-patched.
-
-
A Trice ID is stays the same if the stamp size is changed. Example:
trice( iD(12345), "Hi!" ); // original
TRice( iD(12345), "Hi!" ); // manually changed stamp size and then "trice i" performed.
21.6. User Code Un-Patching
21.7. ID Usage Options
- Per default the
trice insert
command chooses randomly a so far unused ID for new format strings and extendstil.json
. - After
trice c
all src IDs are removed or 0. In this state the src should go into the version management system.
21.8. General ID Management Information
- The trice ID-instead-of-String idea lives from pre-compile patching of the user code.
- The user has full control how to deal with that.
- There are 3 options and the user has to decide which fits best for him.
- Each format string gets its unique trice ID. If the same format string is used on different source code locations it gets different trice IDs this way allowing a reliable location information.
21.9. Option 1: Let the inserted Trice ID be a Part of the User Code
- This is the legacy method. It allows unchanged src translation into code without using the trice tool.
- It is very robust and maybe needed in nasty debugging situations.
- It allows to reconstruct lost til.json information.
- Recommendet for small projects.
21.10. Option 2: Cleaning in a Post-build process
- The code is visually free of IDs all the time.
21.11. Option 3: Cleaning on Repository Check-In
- The code is visually free of IDs only inside the repository.
22. Changelog
Details
-
| Date | Version | Comment |
| ----------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| 2022-MAR-15 | 0.0.0 | Initial Draft |
| 2022-MAR-15 | 0.1.0 | Minor corrections applied. |
| 2022-MAR-15 | 0.2.0 | Sigil byte encoding clarified. |
| 2022-MAR-15 | 0.3.0 | Forward versus backward COBS encoding discussion inserted. |
| 2022-MAR-15 | 0.4.0 | Forward versus backward COBS encoding reworked. Disruption detection added. |
| 2022-MAR-15 | 0.5.0 | Minor corrections |
| 2022-MAR-16 | 0.6.0 | TCOBS prime number comment added, simplified |
| 2022-MAR-17 | 0.7.0 | TCOBS move into a separate [TCOBS Specification](/trice/docs/TCOBSSpecification.html), Framing more detailed. |
| 2022-MAR-20 | 0.7.1 | Contributive *Trice* extension remark added. |
| 2022-APR-12 | 0.8.0 | TREX mainstream format changed to timestamps immediate after ID. |
| 2022-MAY-20 | 0.8.1 | Formatting, Spelling |
| 2022-JUN-19 | 0.9.0 | Implementation hint added to chapter Framing. |
| 2022-AUG-14 | 0.10.0 | Chapter ID Management added |
| 2022-AUG-19 | 0.11.0 | Chapter Main Stream Logs changed/extended |
| 2022-SEP-15 | 0.11.1 | TS32, TS16, NOTS, MOD7 added |
| 2022-OCT-08 | 0.11.2 | S0...X3 added |
| 2022-NOV-28 | 0.11.3 | +[#337](https://github.com/rokath/trice/issues/337) in [Framing](#Framing) |
| 2022-DEC-11 | 0.12.0 | restructured |
| 2022-DEC-13 | 0.13.0 | unneeded text removed, some clarifications |
| 2023-JAN-14 | 0.14.0 | Formatting improved, [1. Trice User Interface - Quick Start](#1--trice-user-interface---quick-start) added. |
| 2023-JAN-14 | 0.15.0 | [5.1. The `trice insert` algorithm](#51-the-trice-insert-algorithm) added |
| 2023-JAN-21 | 0.15.1 | Corrections |
| 2023-FEB-25 | 0.16.0 | Many parts reworked and restructured |
| 2023-JUN-10 | 0.17.0 | trice insert algorithm refined |
| 2023-AUG-03 | 0.18.0 | update ---> insert |
| 2024-AUG-18 | 0.19.0 | Mainly updates to current Trice version v0.66.0 |
| 2024-SEP-17 | 0.20.0 | TCP4 input hint added |
| 2024-SEP-25 | 0.21.0 | Chapter "Target Macros" added |
| 2024-NOV-11 | 0.22.0 | Whole document re-read aud updated. |
<!β
_### 3. TREX (TRice EXtendable) encoding
- The extendable encoding leaves options for user specific data mixable with trice data. This allows filtering of the framed data by just checking a bit pattern.
- The IDs inside the source code are a βdealbreakerβ as bora mentioned in his comment. In fact it is not acceptable for library code used in several projects. An improved approach could look like this:
TRICE( id(0), "...", ...); // a trice without stamp
TRICE( Id(0), "...", ...); // a trice with a 16-bit stamp
TRICE( ID(0), "...", ...); // a trice with a 32-bit stamp
For the implementation of the optional Trice extensions (see below), a til.json
format extension is needed because several files are unhandy. Both til.json
formats will be accepted in the future. β>
<!β
- New Trice macros are writable without the ID, so when
trice i
is executed, a CLI switch controls the ID type selection:- The update switch
-stamp 32
defaults new IDΒ΄s toID
. - The update switch
-stamp 16
defaults new IDΒ΄s toId
. - The update switch
-stamp 0
defaults new IDΒ΄s toid
. - The update switch
-stamp to32
converts allid
andId
toID
. - The update switch
-stamp to16
converts allid
andID
toId
. - The update switch
-stamp to0
converts allID
andId
toid
.
- The update switch
trice log
:- The log switch
-ttsf
is the same as-ttsf32
. - There is a new log switch
ttsf16
for the 16 bit timestamps. - The
trice
tool alignes Trice messages with different timestamp sizes.
- The log switch
-
The trice tool supports several encodings, old projects should be usable with newer trice tool versions by applying the
-encoding TLE
switch. - The TREX (TRice EXtendable) encoding format is planned to be stable. The with name βCOBSβ branded Trice v0.48.0 encoding is not optimal concerning the generated data amount:
- See discussion #253 Save trice COBS encoded data on target and view it later on PC.
- The location information is transmitted as 16 bit file ID plus 16 bit line number. It is possible to generate during
trice insert
an additional fileli.json
containing the location information for each Trice ID avoiding the additional 4 bytes this way. But this could cause assignment issues, when the same Trice ID is used at different locations (see https://github.com/rokath/trice/discussions/264). But it is possible to drop the optiontrice i -sharedIDs
. - The 32-bit βCOBSβ package descriptor is overkill for allowing user data and dropped in TREX.
- The additional padding bytes to achieve 32 bit sizes are not needed and dropped in TREX. The user could add them by himself if really needed.
- The 4 timestamp bytes in front of each Trice demand the βCOBSβ package descriptor. The timestamp should go inside the Trice message and be optionally smaller. That is done in TREX.
-
There is no guaranty for compatibility with legacy target trice versions but the aim is to provide it.
- The Trice v0.48.0 user syntax will remain mainly unchanged. The letter case of the ID codes the target timestamp size. (see below)
- The as βCOBSβ branded legacy v0.48.0 Trice encoding will stay unchanged as an option for compatibility. But it will not be the default encoding anymore. To use newer trice tool versions with legacy projects the CLI switch
-encoding TLE
needs to be used. - The option
-sharedIDs
will be further available but depreciated to avoid location assignment issues. - Legacy projects which used the option
-sharedIDs
will still work even with ali.json
file. A several times used ID will get an assignment of one of the locations. - The issue #242 Add target context option could get the label βwontfixβ. When a task ID is needed, it could be also a data value in such cases.
- The same user source files usable with the legacy Trice βCOBSβ encoding and the proposed additional TREX encoding. They will have 16 bit stamps instead of 32-bits if you keep the sub macros
Id(n)
. - Exchange individually to
ID(n)
to get 32-bit timestamps back. - Exchange individually to
id(n)
to avoid timestamps. - User data are in separate TCOBS packages encoded. When Trices are accumulated in a double half buffer, their separation in TCOBS packages is possible until the first extended Trice. Because of the generally unknown extended Trice length from this point, all following Trices in this half buffer need to go in one TCOBS package (including optional padding bytes) what is ok. The only disadvantage with this is, that in case of a data disruption at this place, several Trice messages can get lost.
Possible better implementation: See issue #290
COBS: See #337
TRICE( S0, "...", ...); // a trice without stamp
TRICE( S2, "...", ...); // a trice with a 16-bit stamp
TRICE( S4, "...", ...); // a trice with a 32-bit stamp
TRICE( S8, "...", ...); // a trice with a 64-bit stamp
TRICE( X0, "...", ...); // an extended type 0 trice
TRICE( X1, "...", ...); // an extended type 1 trice
TRICE( X2, "...", ...); // an extended type 2 trice
TRICE( X3, "...", ...); // an extended type 3 trice
- When editing, the user needs to write only
TRICE( "...", ...);
and the trice tool inserts a S0, S2, S4 or S8 automatically according to the used-stamp
switch parameter. - After repository check-out and before compiling, following substitutions are done using
trice -u
:TRICE( S0, "...", ...);
βTRICE( id(0), "...", ...);
βTRICE( id(12345), "...", ...);
TRICE( S2, "...", ...);
βTRICE( Id(0), "...", ...);
βTRICE( Id(12345), "...", ...);
TRICE( S4, "...", ...);
βTRICE( ID(0), "...", ...);
βTRICE( ID(12345), "...", ...);
TRICE( S8, "...", ...);
βTRICE( iD(0), "...", ...);
βTRICE( ID(12345), "...", ...);
- After compiling and before repository check-in, following substitutions are done using
trice -z
:TRICE( id(12345), "...", ...);
βTRICE( id(0), "...", ...);
βTRICE( S0, "...", ...);
TRICE( Id(12345), "...", ...);
βTRICE( Id(0), "...", ...);
βTRICE( S2, "...", ...);
TRICE( ID(12345), "...", ...);
βTRICE( ID(0), "...", ...);
βTRICE( S4, "...", ...);
TRICE( iD(12345), "...", ...);
βTRICE( iD(0), "...", ...);
βTRICE( S8, "...", ...);
- The project specific
til.json
contains all IDs and duringtrice i
the same IDs are used again for the same trice statement. For new or modified trices new IDs a chosen andtil.json
is extended as usual. - Identical trices should have different IDs for the correctness of the location information. The switch
-sharedIDs
is obsolete and depreciated. - There is no guaranty each trice gets its old ID back, if for example 5 identical trices with different IDs exist, but the probability for an exact restore can made high using the previous
li.json
file. Proposed method:- When
trice -u
is executed, the previousli.json
is read into an internalli_1.map
andli.json
is reset to be an empty file and that is red intoli.map
. - The
til.json
is read into alu
as already done, but the reversalflu
list format gets an ID slice assigned to each trice. - Trices occurring only once, what are probably the most, contain an ID slice of length 1.
- If a trice occurs for example 5 times its ID slice has length 5 containing 5 different IDs.
- When the
trice -u
command finds a trice with ID slice length > 1, it looks intoli_1.map
for all possible IDs and compares the location information with the actual location:- If no matching file name is found, a new ID is generated.
- If file name is identical, the ID with the minimum difference to the line number is chosen if not already used.
- Because all assigned IDs go into the
li.map
this is possible to check. - If all IDs in the slice with identical file name are used, a new ID is generated.
- Of course there are cases possible, where some unwanted ID βshiftβ happens. But we have to consider, that first we are talking about rare identical trices and that such case, if, only happens once with the result, that the
til.json
file adds a bit data garbage. Atil.json
cleaning is always possible, but you loose history then.
- When
6.1. Trice format
- Parameter data bytes start after the optional timestamp.
- N is the parameter data bytes count. Padding bytes are not counted.
- Usually N is < 127 but for buffer or string transfer N can get up to 32767 (15 bits).
- When N > 127 (s==1)
NC
is replaced by1nnnnnnn nnnnnnnn
. C is incremented with each Trice but not transmitted when:- N > 127
- extended Trice without C
_##### 3.2. Framing with TCOBS encoding
- For maximum storage speed each trice message starts at a 32-bit boundary and has 1-3 padding bytes.
- In direct mode only a single message needs handling.
- In deferred mode after half buffer swap any count of trice messages is in the buffer.
- There are different policies possible:
- TRICE_FAST_MULTI_MODE: Compact buffer by removing all padding bytes, encode it as a single package, append one 0-delimiter and transmit. This allows to reduce the transmitted data amount by paying the price of possibly more data lost in case of an error. Also the data interpretation can perform less checks.
- TRICE_SAFE_SINGLE_MODE: Encode each buffer separate, append a 0-delimiter for each and pack them all together before transmitting. This increases the transmit data slightly but minimizes the amount of lost data in case of a data disruption.